// 6 april 2015

// TODO add a uiVerifyControlType() function that can be used by control implementations to verify controls

// TODOs
// - make getters that return whether something exists accept a NULL pointer to discard the value (and thus only return that the thing exists?)
// - const-correct everything
// - normalize documentation between typedefs and structs

/**
 * @defgroup container Container controls
 * @defgroup dataEntry Data entry controls
 * @defgroup static Static controls
 * @defgroup button Buttons
 * @defgroup dialogWindow Dialog windows
 * @defgroup menu Menus
 * @defgroup table Tables
 */

#ifndef __LIBUI_UI_H__
#define __LIBUI_UI_H__

#include <stddef.h>
#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

// this macro is generated by cmake
#ifdef libui_EXPORTS
#ifdef _WIN32
#define _UI_EXTERN __declspec(dllexport) extern
#else
#define _UI_EXTERN __attribute__((visibility("default"))) extern
#endif
#else
// TODO add __declspec(dllimport) on windows, but only if not static
#define _UI_EXTERN extern
#endif

// C++ is really really really really really really dumb about enums, so screw that and just make them anonymous
// This has the advantage of being ABI-able should we ever need an ABI...
#define _UI_ENUM(s) typedef unsigned int s; enum

// This constant is provided because M_PI is nonstandard.
// This comes from Go's math.Pi, which in turn comes from http://oeis.org/A000796.
#define uiPi 3.14159265358979323846264338327950288419716939937510582097494459

// TODO uiBool?

// uiForEach represents the return value from one of libui's various ForEach functions.
_UI_ENUM(uiForEach) {
	uiForEachContinue,
	uiForEachStop,
};

typedef struct uiInitOptions uiInitOptions;

struct uiInitOptions {
	size_t Size;
};

_UI_EXTERN const char *uiInit(uiInitOptions *options);
_UI_EXTERN void uiUninit(void);
_UI_EXTERN void uiFreeInitError(const char *err);

_UI_EXTERN void uiMain(void);
_UI_EXTERN void uiMainSteps(void);
_UI_EXTERN int uiMainStep(int wait);
_UI_EXTERN void uiQuit(void);

_UI_EXTERN void uiQueueMain(void (*f)(void *data), void *data);

// TODO standardize the looping behavior return type, either with some enum or something, and the test expressions throughout the code
// TODO figure out what to do about looping and the exact point that the timer is rescheduled so we can document it; see https://github.com/andlabs/libui/pull/277
// TODO (also in the above link) document that this cannot be called from any thread, unlike uiQueueMain()
// TODO document that the minimum exact timing, either accuracy (timer burst, etc.) or granularity (15ms on Windows, etc.), is OS-defined
// TODO also figure out how long until the initial tick is registered on all platforms to document
// TODO also add a comment about how useful this could be in bindings, depending on the language being bound to
_UI_EXTERN void uiTimer(int milliseconds, int (*f)(void *data), void *data);

_UI_EXTERN void uiOnShouldQuit(int (*f)(void *data), void *data);


/**
 * Free the memory of a returned string.
 *
 * @note Every time a string is returned from the library, this method should be called.
 *       Examples of these functions are uiWindowTitle, uiOpenFile, uiSaveFile, and uiEntryText.
 *       It is not required for input strings, e.g. in uiWindowSetTitle.
 *
 * @param text The string to free memory
 */
_UI_EXTERN void uiFreeText(char *text);


/**
 * Base class for GUI controls providing common methods.
 *
 * @struct uiControl
 */
typedef struct uiControl uiControl;
struct uiControl {
	uint32_t Signature;
	uint32_t OSSignature;
	uint32_t TypeSignature;
	void (*Destroy)(uiControl *);
	uintptr_t (*Handle)(uiControl *);
	uiControl *(*Parent)(uiControl *);
	void (*SetParent)(uiControl *, uiControl *);
	int (*Toplevel)(uiControl *);
	int (*Visible)(uiControl *);
	void (*Show)(uiControl *);
	void (*Hide)(uiControl *);
	int (*Enabled)(uiControl *);
	void (*Enable)(uiControl *);
	void (*Disable)(uiControl *);
};
// TOOD add argument names to all arguments
#define uiControl(this) ((uiControl *) (this))

/**
 * Dispose and free all allocated resources.
 *
 * The platform specific APIs that actually destroy a control (and its children) are called.
 *
 * @note Most of the time is needed to be used directly only on the top level windows.
 *
 * @param c uiControl instance.
 * @todo Document ownership.
 * @memberof uiControl
 */
_UI_EXTERN void uiControlDestroy(uiControl *c);

/**
 * Returns the control's OS-level handle.
 *
 * @param c uiControl instance.
 * @returns OS-level handle.
 * @memberof uiControl
 */
_UI_EXTERN uintptr_t uiControlHandle(uiControl *c);

/**
 * Returns the parent control.
 *
 * @param c uiControl instance.
 * @returns The parent control, `NULL` if detached.
 * @memberof uiControl
 */
_UI_EXTERN uiControl *uiControlParent(uiControl *c);

/**
 * Sets the control's parent.
 *
 * @param c uiControl instance.
 * @param parent The parent control, `NULL` to detach.
 * @todo Document ownership.
 * @memberof uiControl
 */
_UI_EXTERN void uiControlSetParent(uiControl *c, uiControl *parent);

/**
 * Returns whether or not the control is a top level control.
 *
 * @param c uiControl instance.
 * @returns `TRUE` if top level control, `FALSE` otherwise.
 * @memberof uiControl
 */
_UI_EXTERN int uiControlToplevel(uiControl *c);

/**
 * Returns whether or not the control is visible.
 *
 * @param c uiControl instance.
 * @returns `TRUE` if visible, `FALSE` otherwise.
 * @memberof uiControl
 */
_UI_EXTERN int uiControlVisible(uiControl *c);

/**
 * Shows the control.
 *
 * @param c uiControl instance.
 * @memberof uiControl
 */
_UI_EXTERN void uiControlShow(uiControl *c);

/**
 * Hides the control.
 *
 * @param c uiControl instance.
 * @note Hidden controls do not take up space within the layout.
 * @memberof uiControl
 */
_UI_EXTERN void uiControlHide(uiControl *c);

/**
 * Returns whether or not the control is enabled.
 *
 * Defaults to `true`.
 *
 * @param c uiControl instance.
 * @see uiControlEnabledToUser
 * @memberof uiControl
 */
_UI_EXTERN int uiControlEnabled(uiControl *c);

/**
 * Enables the control.
 *
 * @param c uiControl instance.
 * @memberof uiControl
 */
_UI_EXTERN void uiControlEnable(uiControl *c);

/**
 * Disables the control.
 *
 * @param c uiControl instance.
 * @memberof uiControl
 */
_UI_EXTERN void uiControlDisable(uiControl *c);

/**
 * Allocates a uiControl.
 *
 * Helper to allocate new controls.
 *
 * @param n Size of type to allocate.
 * @todo Document parameters
 * @memberof uiControl @static
 */
_UI_EXTERN uiControl *uiAllocControl(size_t n, uint32_t OSsig, uint32_t typesig, const char *typenamestr);

/**
 * Frees the memory associated with the control reference.
 *
 * @note This method is public only for writing custom controls.
 *
 * @param c uiControl instance.
 * @memberof uiControl
 */
_UI_EXTERN void uiFreeControl(uiControl *c);

/**
 * Makes sure the control's parent can be set to @p parent.
 *
 * @param c uiControl instance.
 * @param parent uiControl instance.
 * @todo Make sure all controls have these
 * @warning This will crash the application if `FALSE`.
 * @memberof uiControl
 */
_UI_EXTERN void uiControlVerifySetParent(uiControl *c, uiControl *parent);

/**
 * Returns whether or not the control can be interacted with by the user.
 *
 * Checks if the control and all it's parents are enabled to make sure it can
 * be interacted with by the user.
 *
 * @param c uiControl instance.
 * @returns `TRUE` if enabled, `FALSE` otherwise.
 * @see uiControlEnabled
 * @memberof uiControl
 */
_UI_EXTERN int uiControlEnabledToUser(uiControl *c);

// TODO Move this to private API? According to old/new.md this should be used by toplevel controls.
_UI_EXTERN void uiUserBugCannotSetParentOnToplevel(const char *type);


/**
 * A control that represents a top-level window.
 *
 * A window contains exactly one child control that occupied the entire window.
 *
 * @note Many of the uiWindow methods should be regarded as mere hints.
 *       The underlying system may override these or even choose to ignore them
 *       completely. This is especially true for many Unix systems.
 *
 * @warning A uiWindow can NOT be a child of another uiControl.
 *
 * @struct uiWindow
 * @extends uiControl
 * @ingroup container
 */
typedef struct uiWindow uiWindow;
#define uiWindow(this) ((uiWindow *) (this))

/**
 * Returns the window title.
 *
 * @param w uiWindow instance.
 * @returns The window title text.\n
 *          A `NUL` terminated UTF-8 string.\n
 *          Caller is responsible for freeing the data with `uiFreeText()`.
 * @memberof uiWindow
 */
_UI_EXTERN char *uiWindowTitle(uiWindow *w);

/**
 * Sets the window title.
 *
 * @param w uiWindow instance.
 * @param title Window title text.\n
 *              A valid, `NUL` terminated UTF-8 string.\n
 *              Data is copied internally. Ownership is not transferred.
 * @note This method is merely a hint and may be ignored on unix platforms.
 * @memberof uiWindow
 */
_UI_EXTERN void uiWindowSetTitle(uiWindow *w, const char *title);

/**
 * Gets the window position.
 *
 * Coordinates are measured from the top left corner of the screen.
 *
 * @param w uiWindow instance.
 * @param[out] x X position of the window.
 * @param[out] y Y position of the window.
 * @note This method may return inaccurate or dummy values on Unix platforms.
 * @memberof uiWindow
 */
_UI_EXTERN void uiWindowPosition(uiWindow *w, int *x, int *y);

/**
 * Moves the window to the specified position.
 *
 * Coordinates are measured from the top left corner of the screen.
 *
 * @param w uiWindow instance.
 * @param x New x position of the window.
 * @param y New y position of the window.
 * @note This method is merely a hint and may be ignored on Unix platforms.
 * @memberof uiWindow
 */
_UI_EXTERN void uiWindowSetPosition(uiWindow *w, int x, int y);

/**
 * Registers a callback for when the window moved.
 *
 * @param w uiWindow instance.
 * @param f Callback function.\n
 *          @p sender Back reference to the instance that triggered the callback.\n
 *          @p senderData User data registered with the sender instance.\n
 * @param data User data to be passed to the callback.
 *
 * @note Only one callback can be registered at a time.
 * @note The callback is not triggered when calling uiWindowSetPosition().
 * @memberof uiWindow
 */
_UI_EXTERN void uiWindowOnPositionChanged(uiWindow *w,
	void (*f)(uiWindow *sender, void *senderData), void *data);

/**
 * Gets the window content size.
 *
 * @param w uiWindow instance.
 * @param[out] width Window content width.
 * @param[out] height Window content height.
 * @note The content size does NOT include window decorations like menus or title bars.
 * @memberof uiWindow
 */
_UI_EXTERN void uiWindowContentSize(uiWindow *w, int *width, int *height);

/**
 * Sets the window content size.
 *
 * @param w uiWindow instance.
 * @param width Window content width to set.
 * @param height Window content height to set.
 * @note The content size does NOT include window decorations like menus or title bars.
 * @note This method is merely a hint and may be ignored by the system.
 * @memberof uiWindow
 */
_UI_EXTERN void uiWindowSetContentSize(uiWindow *w, int width, int height);

/**
 * Returns whether or not the window is full screen.
 *
 * @param w uiWindow instance.
 * @returns `TRUE` if full screen, `FALSE` otherwise. [Default: `FALSE`]
 * @memberof uiWindow
 */
_UI_EXTERN int uiWindowFullscreen(uiWindow *w);

/**
 * Sets whether or not the window is full screen.
 *
 * @param w uiWindow instance.
 * @param fullscreen `TRUE` to make window full screen, `FALSE` otherwise.
 * @note This method is merely a hint and may be ignored by the system.
 * @memberof uiWindow
 */
_UI_EXTERN void uiWindowSetFullscreen(uiWindow *w, int fullscreen);

/**
 * Registers a callback for when the window content size is changed.
 *
 * @param w uiWindow instance.
 * @param f Callback function.\n
 *          @p sender Back reference to the instance that triggered the callback.\n
 *          @p senderData User data registered with the sender instance.
 * @param data User data to be passed to the callback.
 *
 * @note The callback is not triggered when calling uiWindowSetContentSize().
 * @note Only one callback can be registered at a time.
 * @memberof uiWindow
 */
_UI_EXTERN void uiWindowOnContentSizeChanged(uiWindow *w,
	void (*f)(uiWindow *sender, void *senderData), void *data);

/**
 * Registers a callback for when the window is to be closed.
 *
 * @param w uiWindow instance.
 * @param f Callback function.\n
 *          @p sender Back reference to the instance that triggered the callback.\n
 *          @p senderData User data registered with the sender instance.\n
 *          Return:\n
 *          `TRUE` to destroys the window.\n
 *          `FALSE` to abort closing and keep the window alive and visible.
 * @param data User data to be passed to the callback.
 *
 * @note Only one callback can be registered at a time.
 * @memberof uiWindow
 */
_UI_EXTERN void uiWindowOnClosing(uiWindow *w,
	int (*f)(uiWindow *sender, void *senderData), void *data);

/**
 * Registers a callback for when the window focus changes.
 *
 * @param w uiWindow instance.
 * @param f Callback function.\n
 *          @p sender Back reference to the instance that triggered the callback.\n
 *          @p senderData User data registered with the sender instance.
 * @param data User data to be passed to the callback.
 *
 * @note Only one callback can be registered at a time.
 * @memberof uiWindow
 */
_UI_EXTERN void uiWindowOnFocusChanged(uiWindow *w,
	void (*f)(uiWindow *sender, void *senderData), void *data);

/**
 * Returns whether or not the window is focused.
 *
 * @param w uiWindow instance.
 * @returns `TRUE` if window is focused, `FALSE` otherwise.
 * @memberof uiWindow
 */
_UI_EXTERN int uiWindowFocused(uiWindow *w);

/**
 * Returns whether or not the window is borderless.
 *
 * @param w uiWindow instance.
 * @returns `TRUE` if window is borderless, `FALSE` otherwise. [Default: `TODO`]
 * @memberof uiWindow
 */
_UI_EXTERN int uiWindowBorderless(uiWindow *w);

/**
 * Sets whether or not the window is borderless.
 *
 * @param w uiWindow instance.
 * @param borderless `TRUE` to make window borderless, `FALSE` otherwise.
 * @note This method is merely a hint and may be ignored by the system.
 * @memberof uiWindow
 */
_UI_EXTERN void uiWindowSetBorderless(uiWindow *w, int borderless);

/**
 * Sets the window's child.
 *
 * @param w uiWindow instance.
 * @param child Control to be made child.
 * @memberof uiWindow
 */
_UI_EXTERN void uiWindowSetChild(uiWindow *w, uiControl *child);

/**
 * Returns whether or not the window has a margin.
 *
 * @param w uiWindow instance.
 * @returns `TRUE` if window has a margin, `FALSE` otherwise. [Default: `FALSE`]
 * @memberof uiWindow
 */
_UI_EXTERN int uiWindowMargined(uiWindow *w);

/**
 * Sets whether or not the window has a margin.
 *
 * The margin size is determined by the OS defaults.
 *
 * @param w uiWindow instance.
 * @param margined `TRUE` to set a window margin, `FALSE` otherwise.
 * @memberof uiWindow
 */
_UI_EXTERN void uiWindowSetMargined(uiWindow *w, int margined);

/**
 * Returns whether or not the window is user resizeable.
 *
 * @param w uiWindow instance.
 * @returns `TRUE` if window is resizable, `FALSE` otherwise. [Default: `TRUE`]
 * @memberof uiWindow
 */
_UI_EXTERN int uiWindowResizeable(uiWindow *w);

/**
 * Sets whether or not the window is user resizeable.
 *
 * @param w uiWindow instance.
 * @param resizeable `TRUE` to make window resizable, `FALSE` otherwise.
 * @note This method is merely a hint and may be ignored by the system.
 * @memberof uiWindow
 */
_UI_EXTERN void uiWindowSetResizeable(uiWindow *w, int resizeable);

/**
 * Creates a new uiWindow.
 *
 * @param title Window title text.\n
 *              A valid, `NUL` terminated UTF-8 string.\n
 *              Data is copied internally. Ownership is not transferred.
 * @param width Window width.
 * @param height Window height.
 * @param hasMenubar Whether or not the window should display a menu bar.
 * @returns A new uiWindow instance.
 * @memberof uiWindow @static
 */
_UI_EXTERN uiWindow *uiNewWindow(const char *title, int width, int height, int hasMenubar);


/**
 * A control that visually represents a button to be clicked by the user to trigger an action.
 *
 * @struct uiButton
 * @extends uiControl
 * @ingroup button
 */
typedef struct uiButton uiButton;
#define uiButton(this) ((uiButton *) (this))

/**
 * Returns the button label text.
 *
 * @param b uiButton instance.
 * @returns The text of the label.\n
 *          A `NUL` terminated UTF-8 string.\n
 *          Caller is responsible for freeing the data with `uiFreeText()`.
 * @memberof uiButton
 */
_UI_EXTERN char *uiButtonText(uiButton *b);

/**
 * Sets the button label text.
 *
 * @param b uiButton instance.
 * @param text Label text.\n
 *             A valid, `NUL` terminated UTF-8 string.\n
 *             Data is copied internally. Ownership is not transferred.
 * @memberof uiButton
 */
_UI_EXTERN void uiButtonSetText(uiButton *b, const char *text);

/**
 * Registers a callback for when the button is clicked.
 *
 * @param b uiButton instance.
 * @param f Callback function.\n
 *          @p sender Back reference to the instance that triggered the callback.\n
 *          @p senderData User data registered with the sender instance.
 * @param data User data to be passed to the callback.
 *
 * @note Only one callback can be registered at a time.
 * @memberof uiButton
 */
_UI_EXTERN void uiButtonOnClicked(uiButton *b,
	void (*f)(uiButton *sender, void *senderData), void *data);

/**
 * Creates a new button.
 *
 * @param text Label text.\n
 *             A valid, `NUL` terminated UTF-8 string.\n
 *             Data is copied internally. Ownership is not transferred.
 * @returns A new uiButton instance.
 * @memberof uiButton @static
 */
_UI_EXTERN uiButton *uiNewButton(const char *text);


/**
 * A boxlike container that holds a group of controls.
 *
 * The contained controls are arranged to be displayed either horizontally or
 * vertically next to each other.
 *
 * @struct uiBox
 * @extends uiControl
 * @ingroup container
 */
typedef struct uiBox uiBox;
#define uiBox(this) ((uiBox *) (this))

/**
 * Appends a control to the box.
 *
 * Stretchy items expand to use the remaining space within the box.
 * In the case of multiple stretchy items the space is shared equally.
 *
 * @param b uiBox instance.
 * @param child Control instance to append.
 * @param stretchy `TRUE` to stretch control, `FALSE` otherwise.
 * @memberof uiBox
 */
_UI_EXTERN void uiBoxAppend(uiBox *b, uiControl *child, int stretchy);

/**
 * Returns the number of controls contained within the box.
 *
 * @param b uiBox instance.
 * @returns Number of children.
 * @memberof uiBox
 */
_UI_EXTERN int uiBoxNumChildren(uiBox *b);

/**
 * Removes the control at @p index from the box.
 *
 * @param b uiBox instance.
 * @param index Index of control to be removed.
 * @note The control neither destroyed nor freed.
 * @memberof uiBox
 */
_UI_EXTERN void uiBoxDelete(uiBox *b, int index);

/**
 * Returns whether or not controls within the box are padded.
 *
 * Padding is defined as space between individual controls.
 *
 * @param b uiBox instance.
 * @returns `TRUE` if controls are padded, `FALSE` otherwise. [Default: `TODO`]
 * @memberof uiBox
 */
_UI_EXTERN int uiBoxPadded(uiBox *b);

/**
 * Sets whether or not controls within the box are padded.
 *
 * Padding is defined as space between individual controls.
 * The padding size is determined by the OS defaults.
 *
 * @param b uiBox instance.
 * @param padded  `TRUE` to make controls padded, `FALSE` otherwise.
 * @memberof uiBox
 */
_UI_EXTERN void uiBoxSetPadded(uiBox *b, int padded);

/**
 * Creates a new horizontal box.
 *
 * Controls within the box are placed next to each other horizontally.
 *
 * @returns A new uiBox instance.
 * @memberof uiBox @static
 */
_UI_EXTERN uiBox *uiNewHorizontalBox(void);

/**
 * Creates a new vertical box.
 *
 * Controls within the box are placed next to each other vertically.
 *
 * @returns A new uiBox instance.
 * @memberof uiBox @static
 */
_UI_EXTERN uiBox *uiNewVerticalBox(void);


/**
 * A control with a user checkable box accompanied by a text label.
 *
 * @struct uiCheckbox
 * @extends uiControl
 * @ingroup dataEntry
 */
typedef struct uiCheckbox uiCheckbox;
#define uiCheckbox(this) ((uiCheckbox *) (this))

/**
 * Returns the checkbox label text.
 *
 * @param c uiCheckbox instance.
 * @returns The text of the label.\n
 *          A `NUL` terminated UTF-8 string.\n
 *          Caller is responsible for freeing the data with `uiFreeText()`.
 * @memberof uiCheckbox
 */
_UI_EXTERN char *uiCheckboxText(uiCheckbox *c);

/**
 * Sets the checkbox label text.
 *
 * @param c uiCheckbox instance.
 * @param text Label text.\n
 *             A valid, `NUL` terminated UTF-8 string.\n
 *             Data is copied internally. Ownership is not transferred.
 * @memberof uiCheckbox
 */
_UI_EXTERN void uiCheckboxSetText(uiCheckbox *c, const char *text);

/**
 * Registers a callback for when the checkbox is toggled by the user.
 *
 * @param c uiCheckbox instance.
 * @param f Callback function.\n
 *          @p sender Back reference to the instance that initiated the callback.\n
 *          @p senderData User data registered with the sender instance.\n
 * @param data User data to be passed to the callback.
 *
 * @note The callback is not triggered when calling uiCheckboxSetChecked().
 * @note Only one callback can be registered at a time.
 * @memberof uiCheckbox
 */
_UI_EXTERN void uiCheckboxOnToggled(uiCheckbox *c,
	void (*f)(uiCheckbox *sender, void *senderData), void *data);

/**
 * Returns whether or the checkbox is checked.
 *
 * @param c uiCheckbox instance.
 * @returns `TRUE` if checked, `FALSE` otherwise. [Default: `FALSE`]
 * @memberof uiCheckbox
 */
_UI_EXTERN int uiCheckboxChecked(uiCheckbox *c);

/**
 * Sets whether or not the checkbox is checked.
 *
 * @param c uiCheckbox instance.
 * @param checked `TRUE` to check box, `FALSE` otherwise.
 * @memberof uiCheckbox
 */
_UI_EXTERN void uiCheckboxSetChecked(uiCheckbox *c, int checked);

/**
 * Creates a new checkbox.
 *
 * @param text Label text.\n
 *             A valid, `NUL` terminated UTF-8 string.\n
 *             Data is copied internally. Ownership is not transferred.
 * @returns A new uiCheckbox instance.
 * @memberof uiCheckbox @static
 */
_UI_EXTERN uiCheckbox *uiNewCheckbox(const char *text);


/**
 * A control with a single line text entry field.
 *
 * @struct uiEntry
 * @extends uiControl
 * @ingroup dataEntry
 */
typedef struct uiEntry uiEntry;
#define uiEntry(this) ((uiEntry *) (this))

/**
 * Returns the entry's text.
 *
 * @param e uiEntry instance.
 * @returns The text of the entry.\n
 *          A `NUL` terminated UTF-8 string.\n
 *          Caller is responsible for freeing the data with `uiFreeText()`.
 * @memberof uiEntry
 */
_UI_EXTERN char *uiEntryText(uiEntry *e);

/**
 * Sets the entry's text.
 *
 * @param e uiEntry instance.
 * @param text Entry text.\n
 *             A valid, `NUL` terminated UTF-8 string.\n
 *             Data is copied internally. Ownership is not transferred.
 * @memberof uiEntry
 */
_UI_EXTERN void uiEntrySetText(uiEntry *e, const char *text);

/**
 * Registers a callback for when the user changes the entry's text.
 *
 * @param e uiEntry instance.
 * @param f Callback function.\n
 *          @p sender Back reference to the instance that initiated the callback.\n
 *          @p senderData User data registered with the sender instance.\n
 * @param data User data to be passed to the callback.
 *
 * @note The callback is not triggered when calling uiEntrySetText().
 * @memberof uiEntry
 */
_UI_EXTERN void uiEntryOnChanged(uiEntry *e,
	void (*f)(uiEntry *sender, void *senderData), void *data);

/**
 * Returns whether or not the entry's text can be changed.
 *
 * @param e uiEntry instance.
 * @returns `TRUE` if read only, `FALSE` otherwise. [Default: `FALSE`]
 * @memberof uiEntry
 */
_UI_EXTERN int uiEntryReadOnly(uiEntry *e);

/**
 * Sets whether or not the entry's text is read only.
 *
 * @param e uiEntry instance.
 * @param readonly `TRUE` to make read only, `FALSE` otherwise.
 * @memberof uiEntry
 */
_UI_EXTERN void uiEntrySetReadOnly(uiEntry *e, int readonly);

/**
 * Creates a new entry.
 *
 * @returns A new uiEntry instance.
 * @memberof uiEntry @static
 */
_UI_EXTERN uiEntry *uiNewEntry(void);

/**
 * Creates a new entry suitable for sensitive inputs like passwords.
 *
 * The entered text is NOT readable by the user but masked as *******.
 *
 * @returns A new uiEntry instance.
 * @memberof uiEntry @static
 */
_UI_EXTERN uiEntry *uiNewPasswordEntry(void);

/**
 * Creates a new entry suitable for search.
 *
 * Some systems will deliberately delay the uiEntryOnChanged() callback for
 * a more natural feel.
 *
 * @returns A new uiEntry instance.
 * @memberof uiEntry @static
 */
_UI_EXTERN uiEntry *uiNewSearchEntry(void);


/**
 * A control that displays non interactive text.
 *
 * @struct uiLabel
 * @extends uiControl
 * @ingroup static
 */
typedef struct uiLabel uiLabel;
#define uiLabel(this) ((uiLabel *) (this))

/**
 * Returns the label text.
 *
 * @param l uiLabel instance.
 * @returns The text of the label.\n
 *          A `NUL` terminated UTF-8 string.\n
 *          Caller is responsible for freeing the data with `uiFreeText()`.
 * @memberof uiLabel
 */
_UI_EXTERN char *uiLabelText(uiLabel *l);

/**
 * Sets the label text.
 *
 * @param l uiLabel instance.
 * @param text Label text.\n
 *             A valid, `NUL` terminated UTF-8 string.\n
 *             Data is copied internally. Ownership is not transferred.
 * @memberof uiLabel
 */
_UI_EXTERN void uiLabelSetText(uiLabel *l, const char *text);

/**
 * Creates a new label.
 *
 * @param text Label text.\n
 *             A valid, `NUL` terminated UTF-8 string.\n
 *             Data is copied internally. Ownership is not transferred.
 * @returns A new uiLabel instance.
 * @memberof uiLabel @static
 */
_UI_EXTERN uiLabel *uiNewLabel(const char *text);


/**
 * A multi page control interface that displays one page at a time.
 *
 * Each page/tab has an associated label that can be selected to switch
 * between pages/tabs.
 *
 * @struct uiTab
 * @extends uiControl
 * @ingroup container
 */
typedef struct uiTab uiTab;
#define uiTab(this) ((uiTab *) (this))

/**
 * Returns the index of the tab selected.
 *
 * @param c uiTab instance.
 * @returns Index of the tab selected
 * @memberof uiTab
 */
_UI_EXTERN int uiTabSelected(uiTab *t);

/**
 * Sets the tab selected.
 *
 * @param c uiTab instance.
 * @param index Index of the tab to be selected
 * @note The @p index must be in the range [0, uiTabNumPages(t) - 1].
 *          If out of bounds, the selection is not changed.
 * @memberof uiTab
 */
_UI_EXTERN void uiTabSetSelected(uiTab *t, int index);

/**
 * Registers a callback for when a tab is selected.
 *
 * @param t uiTab instance.
 * @param f Callback function.\n
 *          @p sender Back reference to the instance that triggered the callback.\n
 *          @p senderData User data registered with the sender instance.
 * @param data User data to be passed to the callback.
 *
 * @note The callback is not triggered when calling uiTabSetSelected(),
 * @note Only one callback can be registered at a time.
 * @memberof uiTab
 */
_UI_EXTERN void uiTabOnSelected(uiTab *t,
        void (*f)(uiTab *sender, void *senderData), void *data);

/**
 * Appends a control in form of a page/tab with label.
 *
 * @param t uiTab instance.
 * @param name Label text.\n
 *             A valid, `NUL` terminated UTF-8 string.\n
 *             Data is copied internally. Ownership is not transferred.
 * @param c Control to append.
 * @memberof uiTab
 */
_UI_EXTERN void uiTabAppend(uiTab *t, const char *name, uiControl *c);

/**
 * Inserts a control in form of a page/tab with label at @p index.
 *
 * @param t uiTab instance.
 * @param name Label text.\n
 *             A valid, `NUL` terminated UTF-8 string.\n
 *             Data is copied internally. Ownership is not transferred.
 * @param index Index at which to insert the control.
 * @param c Control to insert.
 * @memberof uiTab
 */
_UI_EXTERN void uiTabInsertAt(uiTab *t, const char *name, int index, uiControl *c);

/**
 * Removes the control at @p index.
 *
 * @param t uiTab instance.
 * @param index Index of the control to be removed.
 * @note The control is neither destroyed nor freed.
 * @memberof uiTab
 */
_UI_EXTERN void uiTabDelete(uiTab *t, int index);

/**
 * Returns the number of pages contained.
 *
 * @param t uiTab instance.
 * @returns Number of pages.
 * @memberof uiTab
 */
_UI_EXTERN int uiTabNumPages(uiTab *t);

/**
 * Returns whether or not the page/tab at @p index has a margin.
 *
 * @param t uiTab instance.
 * @param index Index to check if it has a margin.
 * @returns `TRUE` if the tab has a margin, `FALSE` otherwise. [Default: `TODO`]
 * @memberof uiTab
 */
_UI_EXTERN int uiTabMargined(uiTab *t, int index);

/**
 * Sets whether or not the page/tab at @p index has a margin.
 *
 * The margin size is determined by the OS defaults.
 *
 * @param t uiTab instance.
 * @param index Index of the tab/page to un/set margin for.
 * @param margined `TRUE` to set a margin for tab at @p index, `FALSE` otherwise.
 * @memberof uiTab
 */
_UI_EXTERN void uiTabSetMargined(uiTab *t, int index, int margined);

/**
 * Creates a new tab container.
 *
 * @return A new uiTab instance.
 * @memberof uiTab @static
 */
_UI_EXTERN uiTab *uiNewTab(void);


/**
 * A control container that adds a label to the contained child control.
 *
 * This control is a great way of grouping related controls in combination with
 * uiBox.
 *
 * A visual box will or will not be drawn around the child control dependent
 * on the underlying OS implementation.
 *
 * @struct uiGroup
 * @extends uiControl
 * @ingroup container
 */
typedef struct uiGroup uiGroup;
#define uiGroup(this) ((uiGroup *) (this))

/**
 * Returns the group title.
 *
 * @param g uiGroup instance.
 * @returns The group title text.\n
 *          A `NUL` terminated UTF-8 string.\n
 *          Caller is responsible for freeing the data with `uiFreeText()`.
 * @memberof uiGroup
 */
_UI_EXTERN char *uiGroupTitle(uiGroup *g);

/**
 * Sets the group title.
 *
 * @param g uiGroup instance.
 * @param title Group title text.\n
 *              A valid, `NUL` terminated UTF-8 string.\n
 *              Data is copied internally. Ownership is not transferred.
 * @memberof uiGroup
 */
_UI_EXTERN void uiGroupSetTitle(uiGroup *g, const char *title);

/**
 * Sets the group's child.
 *
 * @param g uiGroup instance.
 * @param c uiControl child instance, or `NULL`.
 * @memberof uiGroup
 */
_UI_EXTERN void uiGroupSetChild(uiGroup *g, uiControl *c);

/**
 * Returns whether or not the group has a margin.
 *
 * @param g uiGroup instance.
 * @returns `TRUE` if the group has a margin, `FALSE` otherwise. [Default: `TODO`]
 * @memberof uiGroup
 */
_UI_EXTERN int uiGroupMargined(uiGroup *g);

/**
 * Sets whether or not the group has a margin.
 *
 * The margin size is determined by the OS defaults.
 *
 * @param g uiGroup instance.
 * @param margined `TRUE` to set a margin, `FALSE` otherwise.
 * @memberof uiGroup
 */
_UI_EXTERN void uiGroupSetMargined(uiGroup *g, int margined);

/**
 * Creates a new group.
 *
 * @param title Group title text.\n
 *              A valid, `NUL` terminated UTF-8 string.\n
 *              Data is copied internally. Ownership is not transferred.
 * @returns A new uiGroup instance.
 * @memberof uiGroup @static
 */
_UI_EXTERN uiGroup *uiNewGroup(const char *title);


/**
 * A control to display and modify integer values via a text field or +/- buttons.
 *
 * This is a convenient control for having the user enter integer values.
 * Values are guaranteed to be within the specified range.
 *
 * The + button increases the held value by 1.\n
 * The - button decreased the held value by 1.
 *
 * Entering a value out of range will clamp to the nearest value in range.
 *
 * @struct uiSpinbox
 * @extends uiControl
 * @ingroup dataEntry
 */
typedef struct uiSpinbox uiSpinbox;
#define uiSpinbox(this) ((uiSpinbox *) (this))

/**
 * Returns the spinbox value.
 *
 * @param s uiSpinbox instance.
 * @returns Spinbox value.
 * @memberof uiSpinbox
 */
_UI_EXTERN int uiSpinboxValue(uiSpinbox *s);

/**
 * Sets the spinbox value.
 *
 * @param s uiSpinbox instance.
 * @param value Value to set.
 * @note Setting a value out of range will clamp to the nearest value in range.
 * @memberof uiSpinbox
 */
_UI_EXTERN void uiSpinboxSetValue(uiSpinbox *s, int value);

/**
 * Registers a callback for when the spinbox value is changed by the user.
 *
 * @param s uiSpinbox instance.
 * @param f Callback function.\n
 *          @p sender Back reference to the instance that triggered the callback.\n
 *          @p senderData User data registered with the sender instance.
 * @param data User data to be passed to the callback.
 *
 * @note The callback is not triggered when calling uiSpinboxSetValue().
 * @note Only one callback can be registered at a time.
 * @memberof uiSpinbox
 */
_UI_EXTERN void uiSpinboxOnChanged(uiSpinbox *s,
	void (*f)(uiSpinbox *sender, void *senderData), void *data);

/**
 * Creates a new spinbox.
 *
 * The initial spinbox value equals the minimum value.
 *
 * In the current implementation @p min and @p max are swapped if `min>max`.
 * This may change in the future though. See TODO.
 *
 * @param min Minimum value.
 * @param max Maximum value.
 * @returns A new uiSpinbox instance.
 * @todo complain or disallow min>max?
 * @memberof uiSpinbox @static
 */
_UI_EXTERN uiSpinbox *uiNewSpinbox(int min, int max);


/**
 * A control to display and modify integer values via a user draggable slider.
 *
 * Values are guaranteed to be within the specified range.
 *
 * Sliders by default display a tool tip showing the current value when being
 * dragged.
 *
 * Sliders are horizontal only.
 *
 * @struct uiSlider
 * @extends uiControl
 * @ingroup dataEntry
 */
typedef struct uiSlider uiSlider;
#define uiSlider(this) ((uiSlider *) (this))

/**
 * Returns the slider value.
 *
 * @param s uiSlider instance.
 * @returns Slider value.
 * @memberof uiSlider
 */
_UI_EXTERN int uiSliderValue(uiSlider *s);

/**
 * Sets the slider value.
 *
 * @param s uiSlider intance.
 * @param value Value to set.
 * @memberof uiSlider
 */
_UI_EXTERN void uiSliderSetValue(uiSlider *s, int value);

/**
 * Returns whether or not the slider has a tool tip.
 *
 * @param s uiSlider instance.
 * @returns `TRUE` if a tool tip is present, `FALSE` otherwise. [Default `TRUE`]
 * @memberof uiSlider
 */
_UI_EXTERN int uiSliderHasToolTip(uiSlider *s);

/**
 * Sets whether or not the slider has a tool tip.
 *
 * @param s uiSlider instance.
 * @param hasToolTip `TRUE` to display a tool tip, `FALSE` to display no tool tip.
 * @memberof uiSlider
 */
_UI_EXTERN void uiSliderSetHasToolTip(uiSlider *s, int hasToolTip);

/**
 * Registers a callback for when the slider value is changed by the user.
 *
 * @param s uiSlider instance.
 * @param f Callback function.\n
 *          @p sender Back reference to the instance that triggered the callback.\n
 *          @p senderData User data registered with the sender instance.
 * @param data User data to be passed to the callback.
 *
 * @note The callback is not triggered when calling uiSliderSetValue().
 * @note Only one callback can be registered at a time.
 * @memberof uiSlider
 */
_UI_EXTERN void uiSliderOnChanged(uiSlider *s,
	void (*f)(uiSlider *sender, void *senderData), void *data);

/**
 * Registers a callback for when the slider is released from dragging.
 *
 * @param s uiSlider instance.
 * @param f Callback function.\n
 *          @p sender Back reference to the instance that triggered the callback.\n
 *          @p senderData User data registered with the sender instance.
 * @param data User data to be passed to the callback.
 *
 * @note Only one callback can be registered at a time.
 * @memberof uiSlider
 */
_UI_EXTERN void uiSliderOnReleased(uiSlider *s,
	void (*f)(uiSlider *sender, void *senderData), void *data);

/**
 * Sets the slider range.
 *
 * @param s uiSlider instance.
 * @param min Minimum value.
 * @param max Maximum value.
 * @todo Make sure to clamp the slider value to the nearest value in range - should
 *       it be out of range. Call uiSliderOnChanged() in such a case.
 * @memberof uiSlider
 */
_UI_EXTERN void uiSliderSetRange(uiSlider *s, int min, int max);

/**
 * Creates a new slider.
 *
 * The initial slider value equals the minimum value.
 *
 * In the current implementation @p min and @p max are swapped if `min>max`.
 * This may change in the future though. See TODO.
 *
 * @param min Minimum value.
 * @param max Maximum value.
 * @returns A new uiSlider instance.
 * @todo complain or disallow min>max?
 * @memberof uiSlider @static
 */
_UI_EXTERN uiSlider *uiNewSlider(int min, int max);


/**
 * A control that visualizes the progress of a task via the fill level of a horizontal bar.
 *
 * Indeterminate values are supported via an animated bar.
 *
 * @struct uiProgressBar
 * @extends uiControl
 * @ingroup static
 */
typedef struct uiProgressBar uiProgressBar;
#define uiProgressBar(this) ((uiProgressBar *) (this))

/**
 * Returns the progress bar value.
 *
 * @param p uiProgressBar instance.
 * @returns Progress bar value. `[Default 0]`
 * @memberof uiProgressBar
 */
_UI_EXTERN int uiProgressBarValue(uiProgressBar *p);

/**
 * Sets the progress bar value.
 *
 * Valid values are `[0, 100]` for displaying a solid bar imitating a percent
 * value.
 *
 * Use a value of `-1` to render an animated bar to convey an indeterminate
 * value.
 *
 * @param p uiProgressBar instance.
 * @param n Value to set. Integer in the range of `[-1, 100]`.
 * @memberof uiProgressBar
 */
_UI_EXTERN void uiProgressBarSetValue(uiProgressBar *p, int n);

/**
 * Creates a new progress bar.
 *
 * @returns A new uiProgressBar instance.
 * @memberof uiProgressBar @static
 */
_UI_EXTERN uiProgressBar *uiNewProgressBar(void);


/**
 * A control to visually separate controls, horizontally or vertically.
 *
 * @struct uiSeparator
 * @extends uiControl
 * @ingroup static
 */
typedef struct uiSeparator uiSeparator;
#define uiSeparator(this) ((uiSeparator *) (this))

/**
 * Creates a new horizontal separator to separate controls being stacked vertically.
 *
 * @returns A new uiSeparator instance.
 * @memberof uiSeparator @static
 */
_UI_EXTERN uiSeparator *uiNewHorizontalSeparator(void);

/**
 * Creates a new vertical separator to separate controls being stacked horizontally.
 *
 * @returns A new uiSeparator instance.
 * @memberof uiSeparator @static
 */
_UI_EXTERN uiSeparator *uiNewVerticalSeparator(void);


/**
 * A control to select one item from a predefined list of items via a drop down menu.
 *
 * @see uiEditableCombobox.
 * @struct uiCombobox
 * @extends uiControl
 * @ingroup dataEntry
 */
typedef struct uiCombobox uiCombobox;
#define uiCombobox(this) ((uiCombobox *) (this))

/**
 * Appends an item to the combo box.
 *
 * @param c uiCombobox instance.
 * @param text Item text.\n
 *             A valid, `NUL` terminated UTF-8 string.\n
 *             Data is copied internally. Ownership is not transferred.
 * @memberof uiCombobox
 */
_UI_EXTERN void uiComboboxAppend(uiCombobox *c, const char *text);

/**
 * Inserts an item at @p index to the combo box.
 *
 * @param c uiCombobox instance.
 * @param index Index at which to insert the item.
 * @param text Item text.\n
 *             A valid, `NUL` terminated UTF-8 string.\n
 *             Data is copied internally. Ownership is not transferred.
 * @memberof uiCombobox
 */
_UI_EXTERN void uiComboboxInsertAt(uiCombobox *c, int index, const char *text);

/**
 * Deletes an item at @p index from the combo box.
 *
 * @note Deleting the index of the item currently selected will move the
 * selection to the next item in the combo box or `-1` if no such item exists.
 *
 * @param c uiCombobox instance.
 * @param index Index of the item to be deleted.
 * @memberof uiCombobox
 */
_UI_EXTERN void uiComboboxDelete(uiCombobox *c, int index);

/**
 * Deletes all items from the combo box.
 *
 * @param c uiCombobox instance.
 * @memberof uiCombobox
 */
_UI_EXTERN void uiComboboxClear(uiCombobox *c);

/**
 * Returns the number of items contained within the combo box.
 *
 * @param c uiCombobox instance.
 * @returns Number of items.
 * @memberof uiCombobox
 */
_UI_EXTERN int uiComboboxNumItems(uiCombobox *c);

/**
 * Returns the index of the item selected.
 *
 * @param c uiCombobox instance.
 * @returns Index of the item selected, `-1` on empty selection. [Default `-1`]
 * @memberof uiCombobox
 */
_UI_EXTERN int uiComboboxSelected(uiCombobox *c);

/**
 * Sets the item selected.
 *
 * @param c uiCombobox instance.
 * @param index Index of the item to be selected, `-1` to clear selection.
 * @memberof uiCombobox
 */
_UI_EXTERN void uiComboboxSetSelected(uiCombobox *c, int index);

/**
 * Registers a callback for when a combo box item is selected.
 *
 * @param c uiCombobox instance.
 * @param f Callback function.\n
 *          @p sender Back reference to the instance that triggered the callback.\n
 *          @p senderData User data registered with the sender instance.
 * @param data User data to be passed to the callback.
 *
 * @note The callback is not triggered when calling uiComboboxSetSelected(),
 *       uiComboboxInsertAt(), uiComboboxDelete(), or uiComboboxClear().
 * @note Only one callback can be registered at a time.
 * @memberof uiCombobox
 */
_UI_EXTERN void uiComboboxOnSelected(uiCombobox *c,
	void (*f)(uiCombobox *sender, void *senderData), void *data);

/**
 * Creates a new combo box.
 *
 * @returns A new uiCombobox instance.
 * @memberof uiCombobox @static
 */
_UI_EXTERN uiCombobox *uiNewCombobox(void);


/**
 * A control to select one item from a predefined list of items or enter ones own.
 *
 * Predefined items can be selected from a drop down menu.
 *
 * A customary item can be entered by the user via an editable text field.
 *
 * @see uiCombobox
 * @struct uiEditableCombobox
 * @extends uiControl
 * @ingroup dataEntry
 */
typedef struct uiEditableCombobox uiEditableCombobox;
#define uiEditableCombobox(this) ((uiEditableCombobox *) (this))

/**
 * Appends an item to the editable combo box.
 *
 * @param c uiEditableCombobox instance.
 * @param text Item text.\n
 *             A valid, `NUL` terminated UTF-8 string.\n
 *             Data is copied internally. Ownership is not transferred.
 * @memberof uiEditableCombobox
 */
_UI_EXTERN void uiEditableComboboxAppend(uiEditableCombobox *c, const char *text);

/**
 * Returns the text of the editable combo box.
 *
 * This text is either the text of one of the predefined list items or the
 * text manually entered by the user.
 *
 * @param c uiEditableCombobox instance.
 * @returns The editable combo box text.\n
 *          A `NUL` terminated UTF-8 string.\n
 *          Caller is responsible for freeing the data with `uiFreeText()`.
 * @memberof uiEditableCombobox
 */
_UI_EXTERN char *uiEditableComboboxText(uiEditableCombobox *c);

/**
 * Sets the editable combo box text.
 *
 * @param c uiEditableCombobox instance.
 * @param text Text field text.\n
 *             A valid, `NUL` terminated UTF-8 string.\n
 *             Data is copied internally. Ownership is not transferred.
 * @memberof uiEditableCombobox
 */
_UI_EXTERN void uiEditableComboboxSetText(uiEditableCombobox *c, const char *text);

// TODO what do we call a function that sets the currently selected item and fills the text field with it?
// editable comboboxes have no consistent concept of selected item

/**
 * Registers a callback for when an editable combo box item is selected or user text changed.
 *
 * @param c uiEditableCombobox instance.
 * @param f Callback function.\n
 *          @p sender Back reference to the instance that triggered the callback.\n
 *          @p senderData User data registered with the sender instance.
 * @param data User data to be passed to the callback.
 *
 * @note The callback is not triggered when calling uiEditableComboboxSetText().
 * @note Only one callback can be registered at a time.
 * @memberof uiEditableCombobox
 */
_UI_EXTERN void uiEditableComboboxOnChanged(uiEditableCombobox *c,
	void (*f)(uiEditableCombobox *sender, void *senderData), void *data);

/**
 * Creates a new editable combo box.
 *
 * @returns A new uiEditableCombobox instance.
 * @memberof uiEditableCombobox @static
 */
_UI_EXTERN uiEditableCombobox *uiNewEditableCombobox(void);


/**
 * A multiple choice control of check buttons from which only one can be selected at a time.
 *
 * @struct uiRadioButtons
 * @extends uiControl
 * @ingroup dataEntry
 */
typedef struct uiRadioButtons uiRadioButtons;
#define uiRadioButtons(this) ((uiRadioButtons *) (this))

/**
 * Appends a radio button.
 *
 * @param r uiRadioButtons instance.
 * @param text Radio button text.\n
 *             A valid, `NUL` terminated UTF-8 string.\n
 *             Data is copied internally. Ownership is not transferred.
 * @memberof uiRadioButtons
 */
_UI_EXTERN void uiRadioButtonsAppend(uiRadioButtons *r, const char *text);

/**
 * Returns the index of the item selected.
 *
 * @param r uiRadioButtons instance.
 * @returns Index of the item selected, `-1` on empty selection.
 * @memberof uiRadioButtons
 */
_UI_EXTERN int uiRadioButtonsSelected(uiRadioButtons *r);

/**
 * Sets the item selected.
 *
 * @param r uiRadioButtons instance.
 * @param index Index of the item to be selected, `-1` to clear selection.
 * @memberof uiRadioButtons
 */
_UI_EXTERN void uiRadioButtonsSetSelected(uiRadioButtons *r, int index);

/**
 * Registers a callback for when radio button is selected.
 *
 * @param r uiRadioButtons instance.
 * @param f Callback function.\n
 *          @p sender Back reference to the instance that triggered the callback.\n
 *          @p senderData User data registered with the sender instance.
 * @param data User data to be passed to the callback.
 *
 * @note The callback is not triggered when calling uiRadioButtonsSetSelected().
 * @note Only one callback can be registered at a time.
 * @memberof uiRadioButtons
 */
_UI_EXTERN void uiRadioButtonsOnSelected(uiRadioButtons *r,
	void (*f)(uiRadioButtons *sender, void *senderData), void *data);

/**
 * Creates a new radio buttons instance.
 *
 * @returns A new uiRadioButtons instance.
 * @memberof uiRadioButtons @static
 */
_UI_EXTERN uiRadioButtons *uiNewRadioButtons(void);

struct tm;
/**
 * A control to enter a date and/or time.
 *
 * All functions operate on `struct tm` as defined in `<time.h>`.
 *
 * All functions assume local time and do NOT perform any time zone conversions.
 *
 * @warning The `struct tm` members `tm_wday` and `tm_yday` are undefined.
 * @warning The `struct tm` member `tm_isdst` is ignored on windows and should be set to `-1`.
 *
 * @todo for Time: define what values are returned when a part is missing
 *
 * @struct uiDateTimePicker
 * @extends uiControl
 * @ingroup dataEntry
 */
typedef struct uiDateTimePicker uiDateTimePicker;
#define uiDateTimePicker(this) ((uiDateTimePicker *) (this))

/**
 * Returns date and time stored in the data time picker.
 *
 * @param d uiDateTimePicker instance.
 * @param[out] time Date and/or time as local time.
 * @warning The `struct tm` members `tm_wday` and `tm_yday` are undefined.
 * @memberof uiDateTimePicker
 */
_UI_EXTERN void uiDateTimePickerTime(uiDateTimePicker *d, struct tm *time);

/**
 * Sets date and time of the data time picker.
 *
 *
 * @param d uiDateTimePicker instance.
 * @param time Date and/or time as local time.
 * @warning The `struct tm` member `tm_isdst` is ignored on windows and should be set to `-1`.
 * @memberof uiDateTimePicker
 */
_UI_EXTERN void uiDateTimePickerSetTime(uiDateTimePicker *d, const struct tm *time);

/**
 * Registers a callback for when the date time picker value is changed by the user.
 *
 * @param d uiDateTimePicker instance.
 * @param f Callback function.\n
 *          @p sender Back reference to the instance that triggered the callback.\n
 *          @p senderData User data registered with the sender instance.
 * @param data User data to be passed to the callback.
 *
 * @note The callback is not triggered when calling  uiDateTimePickerSetTime().
 * @note Only one callback can be registered at a time.
 * @memberof uiDateTimePicker
 */
_UI_EXTERN void uiDateTimePickerOnChanged(uiDateTimePicker *d,
	void (*f)(uiDateTimePicker *sender, void *senderData), void *data);

/**
 * Creates a new date picker.
 *
 * @returns A new uiDateTimePicker instance.
 * @memberof uiDateTimePicker @static
 */
_UI_EXTERN uiDateTimePicker *uiNewDateTimePicker(void);

/**
 * Creates a new time picker.
 *
 * @returns A new uiDateTimePicker instance.
 * @memberof uiDateTimePicker @static
 */
_UI_EXTERN uiDateTimePicker *uiNewDatePicker(void);

/**
 * Creates a new date and time picker.
 *
 * @returns A new uiDateTimePicker instance.
 * @memberof uiDateTimePicker @static
 */
_UI_EXTERN uiDateTimePicker *uiNewTimePicker(void);


/**
 * A control with a multi line text entry field.
 *
 * @todo provide a facility for entering tab stops?
 * @struct uiMultilineEntry
 * @extends uiControl
 * @ingroup dataEntry
 */
typedef struct uiMultilineEntry uiMultilineEntry;
#define uiMultilineEntry(this) ((uiMultilineEntry *) (this))

/**
 * Returns the multi line entry's text.
 *
 * @param e uiMultilineEntry instance.
 * @returns The containing text.\n
 *          A `NUL` terminated UTF-8 string.\n
 *          Caller is responsible for freeing the data with `uiFreeText()`.
 * @memberof uiMultilineEntry
 */
_UI_EXTERN char *uiMultilineEntryText(uiMultilineEntry *e);

/**
 * Sets the multi line entry's text.
 *
 * @param e uiMultilineEntry instance.
 * @param text Single/multi line text.\n
 *             A valid, `NUL` terminated UTF-8 string.\n
 *             Data is copied internally. Ownership is not transferred.
 * @memberof uiMultilineEntry
 */
_UI_EXTERN void uiMultilineEntrySetText(uiMultilineEntry *e, const char *text);

/**
 * Appends text to the multi line entry's text.
 *
 * @param e uiMultilineEntry instance.
 * @param text Text to append.\n
 *             A valid, `NUL` terminated UTF-8 string.\n
 *             Data is copied internally. Ownership is not transferred.
 * @memberof uiMultilineEntry
 */
_UI_EXTERN void uiMultilineEntryAppend(uiMultilineEntry *e, const char *text);

/**
 * Registers a callback for when the user changes the multi line entry's text.
 *
 * @param e uiMultilineEntry instance.
 * @param f Callback function.\n
 *          @p sender Back reference to the instance that initiated the callback.\n
 *          @p senderData User data registered with the sender instance.\n
 * @param data User data to be passed to the callback.
 *
 * @note The callback is not triggered when calling uiMultilineEntrySetText()
 *       or uiMultilineEntryAppend().
 * @note Only one callback can be registered at a time.
 * @memberof uiMultilineEntry
 */
_UI_EXTERN void uiMultilineEntryOnChanged(uiMultilineEntry *e,
	void (*f)(uiMultilineEntry *sender, void *senderData), void *data);

/**
 * Returns whether or not the multi line entry's text can be changed.
 *
 * @param e uiMultilineEntry instance.
 * @returns `TRUE` if read only, `FALSE` otherwise. [Default: `FALSE`]
 * @memberof uiMultilineEntry
 */
_UI_EXTERN int uiMultilineEntryReadOnly(uiMultilineEntry *e);

/**
 * Sets whether or not the multi line entry's text is read only.
 *
 * @param e uiMultilineEntry instance.
 * @param readonly `TRUE` to make read only, `FALSE` otherwise.
 * @memberof uiMultilineEntry
 */
_UI_EXTERN void uiMultilineEntrySetReadOnly(uiMultilineEntry *e, int readonly);

/**
 * Creates a new multi line entry that visually wraps text when lines overflow.
 *
 * @returns A new uiMultilineEntry instance.
 * @memberof uiMultilineEntry @static
 */
_UI_EXTERN uiMultilineEntry *uiNewMultilineEntry(void);

/**
 * Creates a new multi line entry that scrolls horizontally when lines overflow.
 *
 * @remark Windows does not allow for this style to be changed after creation,
 *         hence the two constructors.
 * @returns A new uiMultilineEntry instance.
 * @memberof uiMultilineEntry @static
 */
_UI_EXTERN uiMultilineEntry *uiNewNonWrappingMultilineEntry(void);


/**
 * A menu item used in conjunction with uiMenu.
 *
 * @struct uiMenuItem
 * @ingroup static menu
 */
typedef struct uiMenuItem uiMenuItem;
#define uiMenuItem(this) ((uiMenuItem *) (this))

/**
 * Enables the menu item.
 *
 * @param m uiMenuItem instance.
 * @memberof uiMenuItem
 */
_UI_EXTERN void uiMenuItemEnable(uiMenuItem *m);

/**
 * Disables the menu item.
 *
 * Menu item is grayed out and user interaction is not possible.
 *
 * @param m uiMenuItem instance.
 * @memberof uiMenuItem
 */
_UI_EXTERN void uiMenuItemDisable(uiMenuItem *m);

/**
 * Registers a callback for when the menu item is clicked.
 *
 * @param m uiMenuItem instance.
 * @param f Callback function.\n
 *          @p sender Back reference to the instance that triggered the callback.\n
 *          @p window Reference to the window from which the callback got triggered.\
 *          @p senderData User data registered with the sender instance.
 * @param data User data to be passed to the callback.
 *
 * @note Only one callback can be registered at a time.
 * @memberof uiMenuItem
 */
_UI_EXTERN void uiMenuItemOnClicked(uiMenuItem *m,
	void (*f)(uiMenuItem *sender, uiWindow *window, void *senderData), void *data);

/**
 * Returns whether or not the menu item's checkbox is checked.
 *
 * To be used only with items created via uiMenuAppendCheckItem().
 *
 * @param m uiMenuItem instance.
 * @returns `TRUE` if checked, `FALSE` otherwise. [Default: `FALSE`]
 * @memberof uiMenuItem
 */
_UI_EXTERN int uiMenuItemChecked(uiMenuItem *m);

/**
 * Sets whether or not the menu item's checkbox is checked.
 *
 * To be used only with items created via uiMenuAppendCheckItem().
 *
 * @param m uiMenuItem instance.
 * @param checked `TRUE` to check menu item checkbox, `FALSE` otherwise.
 * @memberof uiMenuItem
 */
_UI_EXTERN void uiMenuItemSetChecked(uiMenuItem *m, int checked);

/**
 * An application level menu bar.
 *
 * The various operating systems impose different requirements on the
 * creation and placement of menu bar items, hence the abstraction of the
 * items `Quit`, `Preferences` and `About`.
 *
 * An exemplary, cross platform menu bar:
 *
 * - File
 *   * New
 *   * Open
 *   * Save
 *   * Quit, _use uiMenuAppendQuitItem()_
 * - Edit
 *   * Undo
 *   * Redo
 *   * Cut
 *   * Copy
 *   * Paste
 *   * Select All
 *   * Preferences, _use uiMenuAppendPreferencesItem()_
 * - Help
 *   * About, _use uiMenuAppendAboutItem()_
 *
 * @struct uiMenu
 * @ingroup static menu
 */
typedef struct uiMenu uiMenu;
#define uiMenu(this) ((uiMenu *) (this))

/**
 * Appends a generic menu item.
 *
 * @param m uiMenu instance.
 * @param name Menu item text.\n
 *             A `NUL` terminated UTF-8 string.\n
 *             Data is copied internally. Ownership is not transferred.
 * @returns A new uiMenuItem instance.
 * @memberof uiMenu
 */
_UI_EXTERN uiMenuItem *uiMenuAppendItem(uiMenu *m, const char *name);

/**
 * Appends a generic menu item with a checkbox.
 *
 * @param m uiMenu instance.
 * @param name Menu item text.\n
 *             A `NUL` terminated UTF-8 string.\n
 *             Data is copied internally. Ownership is not transferred.
 * @returns A new uiMenuItem instance.
 * @memberof uiMenu
 */
_UI_EXTERN uiMenuItem *uiMenuAppendCheckItem(uiMenu *m, const char *name);

/**
 * Appends a new `Quit` menu item.
 *
 * @param m uiMenu instance.
 * @returns A new uiMenuItem instance.
 * @warning Only one such menu item may exist per application.
 * @memberof uiMenu
 */
_UI_EXTERN uiMenuItem *uiMenuAppendQuitItem(uiMenu *m);

/**
 * Appends a new `Preferences` menu item.
 *
 * @param m uiMenu instance.
 * @returns A new uiMenuItem instance.
 * @warning Only one such menu item may exist per application.
 * @memberof uiMenu
 */
_UI_EXTERN uiMenuItem *uiMenuAppendPreferencesItem(uiMenu *m);

/**
 * Appends a new `About` menu item.
 *
 * @param m uiMenu instance.
 * @warning Only one such menu item may exist per application.
 * @returns A new uiMenuItem instance.
 * @memberof uiMenu
 */
_UI_EXTERN uiMenuItem *uiMenuAppendAboutItem(uiMenu *m);

/**
 * Appends a new separator.
 *
 * @param m uiMenu instance.
 * @memberof uiMenu
 */
_UI_EXTERN void uiMenuAppendSeparator(uiMenu *m);

/**
 * Creates a new menu.
 *
 * Typical values are `File`, `Edit`, `Help`.
 *
 * @param name Menu label.\n
 *             A `NUL` terminated UTF-8 string.\n
 *             Data is copied internally. Ownership is not transferred.
 * @returns A new uiMenu instance.
 * @memberof uiMenu @static
 */
_UI_EXTERN uiMenu *uiNewMenu(const char *name);


/**
 * File chooser dialog window to select a single file.
 *
 * @param parent Parent window.
 * @returns File path, `NULL` on cancel.\n
 *          If path is not `NULL`:\n
 *          TODO: clarify string encoding.
 *          Caller is responsible for freeing the data with `uiFreeText()`.
 * @note File paths are separated by the underlying OS file path separator.
 * @ingroup dataEntry dialogWindow
 */
_UI_EXTERN char *uiOpenFile(uiWindow *parent);

/**
 * Folder chooser dialog window to select a single folder.
 *
 * @param parent Parent window.
 * @returns Folder path, `NULL` on cancel.\n
 *          If path is not `NULL`:\n
 *          TODO: clarify string encoding.
 *          Caller is responsible for freeing the data with `uiFreeText()`.
 * @note File paths are separated by the underlying OS file path separator.
 * @ingroup dataEntry dialogWindow
 */
_UI_EXTERN char *uiOpenFolder(uiWindow *parent);

/**
 * Save file dialog window.
 *
 * The user is asked to confirm overwriting existing files, should the chosen
 * file path already exist on the system.
 *
 * @param parent Parent window.
 * @returns File path, `NULL` on cancel.\n
 *          If path is not `NULL`:\n
 *          TODO: clarify string encoding.
 *          Caller is responsible for freeing the data with `uiFreeText()`.
 * @note File paths are separated by the underlying OS file path separator.
 * @ingroup dataEntry dialogWindow
 */
_UI_EXTERN char *uiSaveFile(uiWindow *parent);

/**
 * Message box dialog window.
 *
 * A message box displayed in a new window indicating a common message.
 *
 * @param parent Parent window.
 * @param title Dialog window title text.\n
 *              A valid, `NUL` terminated UTF-8 string.\n
 *              Data is copied internally. Ownership is not transferred.
 * @param description Dialog message text.\n
 *                    A valid, `NUL` terminated UTF-8 string.\n
 *                    Data is copied internally. Ownership is not transferred.
 * @ingroup dialogWindow
 */
_UI_EXTERN void uiMsgBox(uiWindow *parent, const char *title, const char *description);

/**
 * Error message box dialog window.
 *
 * A message box displayed in a new window indicating an error. On some systems
 * this may invoke an accompanying sound.
 *
 * @param parent Parent window.
 * @param title Dialog window title text.\n
 *              A valid, `NUL` terminated UTF-8 string.\n
 *              Data is copied internally. Ownership is not transferred.
 * @param description Dialog message text.\n
 *                    A valid, `NUL` terminated UTF-8 string.\n
 *                    Data is copied internally. Ownership is not transferred.
 * @ingroup dialogWindow
 */
_UI_EXTERN void uiMsgBoxError(uiWindow *parent, const char *title, const char *description);

typedef struct uiArea uiArea;
typedef struct uiAreaHandler uiAreaHandler;
typedef struct uiAreaDrawParams uiAreaDrawParams;
typedef struct uiAreaMouseEvent uiAreaMouseEvent;
typedef struct uiAreaKeyEvent uiAreaKeyEvent;

typedef struct uiDrawContext uiDrawContext;

struct uiAreaHandler {
	void (*Draw)(uiAreaHandler *, uiArea *, uiAreaDrawParams *);
	// TODO document that resizes cause a full redraw for non-scrolling areas; implementation-defined for scrolling areas
	void (*MouseEvent)(uiAreaHandler *, uiArea *, uiAreaMouseEvent *);
	// TODO document that on first show if the mouse is already in the uiArea then one gets sent with left=0
	// TODO what about when the area is hidden and then shown again?
	void (*MouseCrossed)(uiAreaHandler *, uiArea *, int left);
	void (*DragBroken)(uiAreaHandler *, uiArea *);
	int (*KeyEvent)(uiAreaHandler *, uiArea *, uiAreaKeyEvent *);
};

// TODO RTL layouts?
// TODO reconcile edge and corner naming
_UI_ENUM(uiWindowResizeEdge) {
	uiWindowResizeEdgeLeft,
	uiWindowResizeEdgeTop,
	uiWindowResizeEdgeRight,
	uiWindowResizeEdgeBottom,
	uiWindowResizeEdgeTopLeft,
	uiWindowResizeEdgeTopRight,
	uiWindowResizeEdgeBottomLeft,
	uiWindowResizeEdgeBottomRight,
	// TODO have one for keyboard resizes?
	// TODO GDK doesn't seem to have any others, including for keyboards...
	// TODO way to bring up the system menu instead?
};

#define uiArea(this) ((uiArea *) (this))
// TODO give a better name
// TODO document the types of width and height
_UI_EXTERN void uiAreaSetSize(uiArea *a, int width, int height);
// TODO uiAreaQueueRedraw()
_UI_EXTERN void uiAreaQueueRedrawAll(uiArea *a);
_UI_EXTERN void uiAreaScrollTo(uiArea *a, double x, double y, double width, double height);
// TODO document these can only be called within Mouse() handlers
// TODO should these be allowed on scrolling areas?
// TODO decide which mouse events should be accepted; Down is the only one guaranteed to work right now
// TODO what happens to events after calling this up to and including the next mouse up?
// TODO release capture?
_UI_EXTERN void uiAreaBeginUserWindowMove(uiArea *a);
_UI_EXTERN void uiAreaBeginUserWindowResize(uiArea *a, uiWindowResizeEdge edge);
_UI_EXTERN uiArea *uiNewArea(uiAreaHandler *ah);
_UI_EXTERN uiArea *uiNewScrollingArea(uiAreaHandler *ah, int width, int height);

struct uiAreaDrawParams {
	uiDrawContext *Context;

	// TODO document that this is only defined for nonscrolling areas
	double AreaWidth;
	double AreaHeight;

	double ClipX;
	double ClipY;
	double ClipWidth;
	double ClipHeight;
};

typedef struct uiDrawPath uiDrawPath;
typedef struct uiDrawBrush uiDrawBrush;
typedef struct uiDrawStrokeParams uiDrawStrokeParams;
typedef struct uiDrawMatrix uiDrawMatrix;

typedef struct uiDrawBrushGradientStop uiDrawBrushGradientStop;

_UI_ENUM(uiDrawBrushType) {
	uiDrawBrushTypeSolid,
	uiDrawBrushTypeLinearGradient,
	uiDrawBrushTypeRadialGradient,
	uiDrawBrushTypeImage,
};

_UI_ENUM(uiDrawLineCap) {
	uiDrawLineCapFlat,
	uiDrawLineCapRound,
	uiDrawLineCapSquare,
};

_UI_ENUM(uiDrawLineJoin) {
	uiDrawLineJoinMiter,
	uiDrawLineJoinRound,
	uiDrawLineJoinBevel,
};

// this is the default for botoh cairo and Direct2D (in the latter case, from the C++ helper functions)
// Core Graphics doesn't explicitly specify a default, but NSBezierPath allows you to choose one, and this is the initial value
// so we're good to use it too!
#define uiDrawDefaultMiterLimit 10.0

_UI_ENUM(uiDrawFillMode) {
	uiDrawFillModeWinding,
	uiDrawFillModeAlternate,
};

struct uiDrawMatrix {
	double M11;
	double M12;
	double M21;
	double M22;
	double M31;
	double M32;
};

struct uiDrawBrush {
	uiDrawBrushType Type;

	// solid brushes
	double R;
	double G;
	double B;
	double A;

	// gradient brushes
	double X0;		// linear: start X, radial: start X
	double Y0;		// linear: start Y, radial: start Y
	double X1;		// linear: end X, radial: outer circle center X
	double Y1;		// linear: end Y, radial: outer circle center Y
	double OuterRadius;		// radial gradients only
	uiDrawBrushGradientStop *Stops;
	size_t NumStops;
	// TODO extend mode
	// cairo: none, repeat, reflect, pad; no individual control
	// Direct2D: repeat, reflect, pad; no individual control
	// Core Graphics: none, pad; before and after individually
	// TODO cairo documentation is inconsistent about pad

	// TODO images

	// TODO transforms
};

struct uiDrawBrushGradientStop {
	double Pos;
	double R;
	double G;
	double B;
	double A;
};

struct uiDrawStrokeParams {
	uiDrawLineCap Cap;
	uiDrawLineJoin Join;
	// TODO what if this is 0? on windows there will be a crash with dashing
	double Thickness;
	double MiterLimit;
	double *Dashes;
	// TOOD what if this is 1 on Direct2D?
	// TODO what if a dash is 0 on Cairo or Quartz?
	size_t NumDashes;
	double DashPhase;
};

_UI_EXTERN uiDrawPath *uiDrawNewPath(uiDrawFillMode fillMode);
_UI_EXTERN void uiDrawFreePath(uiDrawPath *p);

_UI_EXTERN void uiDrawPathNewFigure(uiDrawPath *p, double x, double y);
_UI_EXTERN void uiDrawPathNewFigureWithArc(uiDrawPath *p, double xCenter, double yCenter, double radius, double startAngle, double sweep, int negative);
_UI_EXTERN void uiDrawPathLineTo(uiDrawPath *p, double x, double y);
// notes: angles are both relative to 0 and go counterclockwise
// TODO is the initial line segment on cairo and OS X a proper join?
// TODO what if sweep < 0?
_UI_EXTERN void uiDrawPathArcTo(uiDrawPath *p, double xCenter, double yCenter, double radius, double startAngle, double sweep, int negative);
_UI_EXTERN void uiDrawPathBezierTo(uiDrawPath *p, double c1x, double c1y, double c2x, double c2y, double endX, double endY);
// TODO quadratic bezier
_UI_EXTERN void uiDrawPathCloseFigure(uiDrawPath *p);

// TODO effect of these when a figure is already started
_UI_EXTERN void uiDrawPathAddRectangle(uiDrawPath *p, double x, double y, double width, double height);

_UI_EXTERN int uiDrawPathEnded(uiDrawPath *p);
_UI_EXTERN void uiDrawPathEnd(uiDrawPath *p);

_UI_EXTERN void uiDrawStroke(uiDrawContext *c, uiDrawPath *path, uiDrawBrush *b, uiDrawStrokeParams *p);
_UI_EXTERN void uiDrawFill(uiDrawContext *c, uiDrawPath *path, uiDrawBrush *b);

// TODO primitives:
// - rounded rectangles
// - elliptical arcs
// - quadratic bezier curves

_UI_EXTERN void uiDrawMatrixSetIdentity(uiDrawMatrix *m);
_UI_EXTERN void uiDrawMatrixTranslate(uiDrawMatrix *m, double x, double y);
_UI_EXTERN void uiDrawMatrixScale(uiDrawMatrix *m, double xCenter, double yCenter, double x, double y);
_UI_EXTERN void uiDrawMatrixRotate(uiDrawMatrix *m, double x, double y, double amount);
_UI_EXTERN void uiDrawMatrixSkew(uiDrawMatrix *m, double x, double y, double xamount, double yamount);
_UI_EXTERN void uiDrawMatrixMultiply(uiDrawMatrix *dest, uiDrawMatrix *src);
_UI_EXTERN int uiDrawMatrixInvertible(uiDrawMatrix *m);
_UI_EXTERN int uiDrawMatrixInvert(uiDrawMatrix *m);
_UI_EXTERN void uiDrawMatrixTransformPoint(uiDrawMatrix *m, double *x, double *y);
_UI_EXTERN void uiDrawMatrixTransformSize(uiDrawMatrix *m, double *x, double *y);

_UI_EXTERN void uiDrawTransform(uiDrawContext *c, uiDrawMatrix *m);

// TODO add a uiDrawPathStrokeToFill() or something like that
_UI_EXTERN void uiDrawClip(uiDrawContext *c, uiDrawPath *path);

_UI_EXTERN void uiDrawSave(uiDrawContext *c);
_UI_EXTERN void uiDrawRestore(uiDrawContext *c);

// uiAttribute stores information about an attribute in a
// uiAttributedString.
//
// You do not create uiAttributes directly; instead, you create a
// uiAttribute of a given type using the specialized constructor
// functions. For every Unicode codepoint in the uiAttributedString,
// at most one value of each attribute type can be applied.
//
// uiAttributes are immutable and the uiAttributedString takes
// ownership of the uiAttribute object once assigned, copying its
// contents as necessary.
// TODO define whether all this, for both uiTableValue and uiAttribute, is undefined behavior or a caught error
typedef struct uiAttribute uiAttribute;

// @role uiAttribute destructor
// uiFreeAttribute() frees a uiAttribute. You generally do not need to
// call this yourself, as uiAttributedString does this for you. In fact,
// it is an error to call this function on a uiAttribute that has been
// given to a uiAttributedString. You can call this, however, if you
// created a uiAttribute that you aren't going to use later.
_UI_EXTERN void uiFreeAttribute(uiAttribute *a);

// uiAttributeType holds the possible uiAttribute types that may be
// returned by uiAttributeGetType(). Refer to the documentation for
// each type's constructor function for details on each type.
_UI_ENUM(uiAttributeType) {
	uiAttributeTypeFamily,
	uiAttributeTypeSize,
	uiAttributeTypeWeight,
	uiAttributeTypeItalic,
	uiAttributeTypeStretch,
	uiAttributeTypeColor,
	uiAttributeTypeBackground,
	uiAttributeTypeUnderline,
	uiAttributeTypeUnderlineColor,
	uiAttributeTypeFeatures,
};

// uiAttributeGetType() returns the type of a.
// TODO I don't like this name
_UI_EXTERN uiAttributeType uiAttributeGetType(const uiAttribute *a);

// uiNewFamilyAttribute() creates a new uiAttribute that changes the
// font family of the text it is applied to. family is copied; you do not
// need to keep it alive after uiNewFamilyAttribute() returns. Font
// family names are case-insensitive.
_UI_EXTERN uiAttribute *uiNewFamilyAttribute(const char *family);

// uiAttributeFamily() returns the font family stored in a. The
// returned string is owned by a. It is an error to call this on a
// uiAttribute that does not hold a font family.
_UI_EXTERN const char *uiAttributeFamily(const uiAttribute *a);

// uiNewSizeAttribute() creates a new uiAttribute that changes the
// size of the text it is applied to, in typographical points.
_UI_EXTERN uiAttribute *uiNewSizeAttribute(double size);

// uiAttributeSize() returns the font size stored in a. It is an error to
// call this on a uiAttribute that does not hold a font size.
_UI_EXTERN double uiAttributeSize(const uiAttribute *a);

// uiTextWeight represents possible text weights. These roughly
// map to the OS/2 text weight field of TrueType and OpenType
// fonts, or to CSS weight numbers. The named constants are
// nominal values; the actual values may vary by font and by OS,
// though this isn't particularly likely. Any value between
// uiTextWeightMinimum and uiTextWeightMaximum, inclusive,
// is allowed.
//
// Note that due to restrictions in early versions of Windows, some
// fonts have "special" weights be exposed in many programs as
// separate font families. This is perhaps most notable with
// Arial Black. libui does not do this, even on Windows (because the
// DirectWrite API libui uses on Windows does not do this); to
// specify Arial Black, use family Arial and weight uiTextWeightBlack.
_UI_ENUM(uiTextWeight) {
	uiTextWeightMinimum = 0,
	uiTextWeightThin = 100,
	uiTextWeightUltraLight = 200,
	uiTextWeightLight = 300,
	uiTextWeightBook = 350,
	uiTextWeightNormal = 400,
	uiTextWeightMedium = 500,
	uiTextWeightSemiBold = 600,
	uiTextWeightBold = 700,
	uiTextWeightUltraBold = 800,
	uiTextWeightHeavy = 900,
	uiTextWeightUltraHeavy = 950,
	uiTextWeightMaximum = 1000,
};

// uiNewWeightAttribute() creates a new uiAttribute that changes the
// weight of the text it is applied to. It is an error to specify a weight
// outside the range [uiTextWeightMinimum,
// uiTextWeightMaximum].
_UI_EXTERN uiAttribute *uiNewWeightAttribute(uiTextWeight weight);

// uiAttributeWeight() returns the font weight stored in a. It is an error
// to call this on a uiAttribute that does not hold a font weight.
_UI_EXTERN uiTextWeight uiAttributeWeight(const uiAttribute *a);

// uiTextItalic represents possible italic modes for a font. Italic
// represents "true" italics where the slanted glyphs have custom
// shapes, whereas oblique represents italics that are merely slanted
// versions of the normal glyphs. Most fonts usually have one or the
// other.
_UI_ENUM(uiTextItalic) {
	uiTextItalicNormal,
	uiTextItalicOblique,
	uiTextItalicItalic,
};

// uiNewItalicAttribute() creates a new uiAttribute that changes the
// italic mode of the text it is applied to. It is an error to specify an
// italic mode not specified in uiTextItalic.
_UI_EXTERN uiAttribute *uiNewItalicAttribute(uiTextItalic italic);

// uiAttributeItalic() returns the font italic mode stored in a. It is an
// error to call this on a uiAttribute that does not hold a font italic
// mode.
_UI_EXTERN uiTextItalic uiAttributeItalic(const uiAttribute *a);

// uiTextStretch represents possible stretches (also called "widths")
// of a font.
//
// Note that due to restrictions in early versions of Windows, some
// fonts have "special" stretches be exposed in many programs as
// separate font families. This is perhaps most notable with
// Arial Condensed. libui does not do this, even on Windows (because
// the DirectWrite API libui uses on Windows does not do this); to
// specify Arial Condensed, use family Arial and stretch
// uiTextStretchCondensed.
_UI_ENUM(uiTextStretch) {
	uiTextStretchUltraCondensed,
	uiTextStretchExtraCondensed,
	uiTextStretchCondensed,
	uiTextStretchSemiCondensed,
	uiTextStretchNormal,
	uiTextStretchSemiExpanded,
	uiTextStretchExpanded,
	uiTextStretchExtraExpanded,
	uiTextStretchUltraExpanded,
};

// uiNewStretchAttribute() creates a new uiAttribute that changes the
// stretch of the text it is applied to. It is an error to specify a strech
// not specified in uiTextStretch.
_UI_EXTERN uiAttribute *uiNewStretchAttribute(uiTextStretch stretch);

// uiAttributeStretch() returns the font stretch stored in a. It is an
// error to call this on a uiAttribute that does not hold a font stretch.
_UI_EXTERN uiTextStretch uiAttributeStretch(const uiAttribute *a);

// uiNewColorAttribute() creates a new uiAttribute that changes the
// color of the text it is applied to. It is an error to specify an invalid
// color.
_UI_EXTERN uiAttribute *uiNewColorAttribute(double r, double g, double b, double a);

// uiAttributeColor() returns the text color stored in a. It is an
// error to call this on a uiAttribute that does not hold a text color.
_UI_EXTERN void uiAttributeColor(const uiAttribute *a, double *r, double *g, double *b, double *alpha);

// uiNewBackgroundAttribute() creates a new uiAttribute that
// changes the background color of the text it is applied to. It is an
// error to specify an invalid color.
_UI_EXTERN uiAttribute *uiNewBackgroundAttribute(double r, double g, double b, double a);

// TODO reuse uiAttributeColor() for background colors, or make a new function...

// uiUnderline specifies a type of underline to use on text.
_UI_ENUM(uiUnderline) {
	uiUnderlineNone,
	uiUnderlineSingle,
	uiUnderlineDouble,
	uiUnderlineSuggestion,		// wavy or dotted underlines used for spelling/grammar checkers
};

// uiNewUnderlineAttribute() creates a new uiAttribute that changes
// the type of underline on the text it is applied to. It is an error to
// specify an underline type not specified in uiUnderline.
_UI_EXTERN uiAttribute *uiNewUnderlineAttribute(uiUnderline u);

// uiAttributeUnderline() returns the underline type stored in a. It is
// an error to call this on a uiAttribute that does not hold an underline
// style.
_UI_EXTERN uiUnderline uiAttributeUnderline(const uiAttribute *a);

// uiUnderlineColor specifies the color of any underline on the text it
// is applied to, regardless of the type of underline. In addition to
// being able to specify a custom color, you can explicitly specify
// platform-specific colors for suggestion underlines; to use them
// correctly, pair them with uiUnderlineSuggestion (though they can
// be used on other types of underline as well).
//
// If an underline type is applied but no underline color is
// specified, the text color is used instead. If an underline color
// is specified without an underline type, the underline color
// attribute is ignored, but not removed from the uiAttributedString.
_UI_ENUM(uiUnderlineColor) {
	uiUnderlineColorCustom,
	uiUnderlineColorSpelling,
	uiUnderlineColorGrammar,
	uiUnderlineColorAuxiliary,		// for instance, the color used by smart replacements on macOS or in Microsoft Office
};

// uiNewUnderlineColorAttribute() creates a new uiAttribute that
// changes the color of the underline on the text it is applied to.
// It is an error to specify an underline color not specified in
// uiUnderlineColor.
//
// If the specified color type is uiUnderlineColorCustom, it is an
// error to specify an invalid color value. Otherwise, the color values
// are ignored and should be specified as zero.
_UI_EXTERN uiAttribute *uiNewUnderlineColorAttribute(uiUnderlineColor u, double r, double g, double b, double a);

// uiAttributeUnderlineColor() returns the underline color stored in
// a. It is an error to call this on a uiAttribute that does not hold an
// underline color.
_UI_EXTERN void uiAttributeUnderlineColor(const uiAttribute *a, uiUnderlineColor *u, double *r, double *g, double *b, double *alpha);

// uiOpenTypeFeatures represents a set of OpenType feature
// tag-value pairs, for applying OpenType features to text.
// OpenType feature tags are four-character codes defined by
// OpenType that cover things from design features like small
// caps and swashes to language-specific glyph shapes and
// beyond. Each tag may only appear once in any given
// uiOpenTypeFeatures instance. Each value is a 32-bit integer,
// often used as a Boolean flag, but sometimes as an index to choose
// a glyph shape to use.
//
// If a font does not support a certain feature, that feature will be
// ignored. (TODO verify this on all OSs)
//
// See the OpenType specification at
// https://www.microsoft.com/typography/otspec/featuretags.htm
// for the complete list of available features, information on specific
// features, and how to use them.
// TODO invalid features
typedef struct uiOpenTypeFeatures uiOpenTypeFeatures;

// uiOpenTypeFeaturesForEachFunc is the type of the function
// invoked by uiOpenTypeFeaturesForEach() for every OpenType
// feature in otf. Refer to that function's documentation for more
// details.
typedef uiForEach (*uiOpenTypeFeaturesForEachFunc)(const uiOpenTypeFeatures *otf, char a, char b, char c, char d, uint32_t value, void *data);

// @role uiOpenTypeFeatures constructor
// uiNewOpenTypeFeatures() returns a new uiOpenTypeFeatures
// instance, with no tags yet added.
_UI_EXTERN uiOpenTypeFeatures *uiNewOpenTypeFeatures(void);

// @role uiOpenTypeFeatures destructor
// uiFreeOpenTypeFeatures() frees otf.
_UI_EXTERN void uiFreeOpenTypeFeatures(uiOpenTypeFeatures *otf);

// uiOpenTypeFeaturesClone() makes a copy of otf and returns it.
// Changing one will not affect the other.
_UI_EXTERN uiOpenTypeFeatures *uiOpenTypeFeaturesClone(const uiOpenTypeFeatures *otf);

// uiOpenTypeFeaturesAdd() adds the given feature tag and value
// to otf. The feature tag is specified by a, b, c, and d. If there is
// already a value associated with the specified tag in otf, the old
// value is removed.
_UI_EXTERN void uiOpenTypeFeaturesAdd(uiOpenTypeFeatures *otf, char a, char b, char c, char d, uint32_t value);

// uiOpenTypeFeaturesRemove() removes the given feature tag
// and value from otf. If the tag is not present in otf,
// uiOpenTypeFeaturesRemove() does nothing.
_UI_EXTERN void uiOpenTypeFeaturesRemove(uiOpenTypeFeatures *otf, char a, char b, char c, char d);

// uiOpenTypeFeaturesGet() determines whether the given feature
// tag is present in otf. If it is, *value is set to the tag's value and
// nonzero is returned. Otherwise, zero is returned.
//
// Note that if uiOpenTypeFeaturesGet() returns zero, value isn't
// changed. This is important: if a feature is not present in a
// uiOpenTypeFeatures, the feature is NOT treated as if its
// value was zero anyway. Script-specific font shaping rules and
// font-specific feature settings may use a different default value
// for a feature. You should likewise not treat a missing feature as
// having a value of zero either. Instead, a missing feature should
// be treated as having some unspecified default value.
_UI_EXTERN int uiOpenTypeFeaturesGet(const uiOpenTypeFeatures *otf, char a, char b, char c, char d, uint32_t *value);

// uiOpenTypeFeaturesForEach() executes f for every tag-value
// pair in otf. The enumeration order is unspecified. You cannot
// modify otf while uiOpenTypeFeaturesForEach() is running.
_UI_EXTERN void uiOpenTypeFeaturesForEach(const uiOpenTypeFeatures *otf, uiOpenTypeFeaturesForEachFunc f, void *data);

// uiNewFeaturesAttribute() creates a new uiAttribute that changes
// the font family of the text it is applied to. otf is copied; you may
// free it after uiNewFeaturesAttribute() returns.
_UI_EXTERN uiAttribute *uiNewFeaturesAttribute(const uiOpenTypeFeatures *otf);

// uiAttributeFeatures() returns the OpenType features stored in a.
// The returned uiOpenTypeFeatures object is owned by a. It is an
// error to call this on a uiAttribute that does not hold OpenType
// features.
_UI_EXTERN const uiOpenTypeFeatures *uiAttributeFeatures(const uiAttribute *a);

// uiAttributedString represents a string of UTF-8 text that can
// optionally be embellished with formatting attributes. libui
// provides the list of formatting attributes, which cover common
// formatting traits like boldface and color as well as advanced
// typographical features provided by OpenType like superscripts
// and small caps. These attributes can be combined in a variety of
// ways.
//
// Attributes are applied to runs of Unicode codepoints in the string.
// Zero-length runs are elided. Consecutive runs that have the same
// attribute type and value are merged. Each attribute is independent
// of each other attribute; overlapping attributes of different types
// do not split each other apart, but different values of the same
// attribute type do.
//
// The empty string can also be represented by uiAttributedString,
// but because of the no-zero-length-attribute rule, it will not have
// attributes.
//
// A uiAttributedString takes ownership of all attributes given to
// it, as it may need to duplicate or delete uiAttribute objects at
// any time. By extension, when you free a uiAttributedString,
// all uiAttributes within will also be freed. Each method will
// describe its own rules in more details.
//
// In addition, uiAttributedString provides facilities for moving
// between grapheme clusters, which represent a character
// from the point of view of the end user. The cursor of a text editor
// is always placed on a grapheme boundary, so you can use these
// features to move the cursor left or right by one "character".
// TODO does uiAttributedString itself need this
//
// uiAttributedString does not provide enough information to be able
// to draw itself onto a uiDrawContext or respond to user actions.
// In order to do that, you'll need to use a uiDrawTextLayout, which
// is built from the combination of a uiAttributedString and a set of
// layout-specific properties.
typedef struct uiAttributedString uiAttributedString;

// uiAttributedStringForEachAttributeFunc is the type of the function
// invoked by uiAttributedStringForEachAttribute() for every
// attribute in s. Refer to that function's documentation for more
// details.
typedef uiForEach (*uiAttributedStringForEachAttributeFunc)(const uiAttributedString *s, const uiAttribute *a, size_t start, size_t end, void *data);

// @role uiAttributedString constructor
// uiNewAttributedString() creates a new uiAttributedString from
// initialString. The string will be entirely unattributed.
_UI_EXTERN uiAttributedString *uiNewAttributedString(const char *initialString);

// @role uiAttributedString destructor
// uiFreeAttributedString() destroys the uiAttributedString s.
// It will also free all uiAttributes within.
_UI_EXTERN void uiFreeAttributedString(uiAttributedString *s);

// uiAttributedStringString() returns the textual content of s as a
// '\0'-terminated UTF-8 string. The returned pointer is valid until
// the next change to the textual content of s.
_UI_EXTERN const char *uiAttributedStringString(const uiAttributedString *s);

// uiAttributedStringLength() returns the number of UTF-8 bytes in
// the textual content of s, excluding the terminating '\0'.
_UI_EXTERN size_t uiAttributedStringLen(const uiAttributedString *s);

// uiAttributedStringAppendUnattributed() adds the '\0'-terminated
// UTF-8 string str to the end of s. The new substring will be
// unattributed.
_UI_EXTERN void uiAttributedStringAppendUnattributed(uiAttributedString *s, const char *str);

// uiAttributedStringInsertAtUnattributed() adds the '\0'-terminated
// UTF-8 string str to s at the byte position specified by at. The new
// substring will be unattributed; existing attributes will be moved
// along with their text.
_UI_EXTERN void uiAttributedStringInsertAtUnattributed(uiAttributedString *s, const char *str, size_t at);

// TODO add the Append and InsertAtExtendingAttributes functions
// TODO and add functions that take a string + length

// uiAttributedStringDelete() deletes the characters and attributes of
// s in the byte range [start, end).
_UI_EXTERN void uiAttributedStringDelete(uiAttributedString *s, size_t start, size_t end);

// TODO add a function to uiAttributedString to get an attribute's value at a specific index or in a specific range, so we can edit

// uiAttributedStringSetAttribute() sets a in the byte range [start, end)
// of s. Any existing attributes in that byte range of the same type are
// removed. s takes ownership of a; you should not use it after
// uiAttributedStringSetAttribute() returns.
_UI_EXTERN void uiAttributedStringSetAttribute(uiAttributedString *s, uiAttribute *a, size_t start, size_t end);

// uiAttributedStringForEachAttribute() enumerates all the
// uiAttributes in s. It is an error to modify s in f. Within f, s still
// owns the attribute; you can neither free it nor save it for later
// use.
// TODO reword the above for consistency (TODO and find out what I meant by that)
// TODO define an enumeration order (or mark it as undefined); also define how consecutive runs of identical attributes are handled here and sync with the definition of uiAttributedString itself
_UI_EXTERN void uiAttributedStringForEachAttribute(const uiAttributedString *s, uiAttributedStringForEachAttributeFunc f, void *data);

// TODO const correct this somehow (the implementation needs to mutate the structure)
_UI_EXTERN size_t uiAttributedStringNumGraphemes(uiAttributedString *s);

// TODO const correct this somehow (the implementation needs to mutate the structure)
_UI_EXTERN size_t uiAttributedStringByteIndexToGrapheme(uiAttributedString *s, size_t pos);

// TODO const correct this somehow (the implementation needs to mutate the structure)
_UI_EXTERN size_t uiAttributedStringGraphemeToByteIndex(uiAttributedString *s, size_t pos);

// uiFontDescriptor provides a complete description of a font where
// one is needed. Currently, this means as the default font of a
// uiDrawTextLayout and as the data returned by uiFontButton.
// All the members operate like the respective uiAttributes.
typedef struct uiFontDescriptor uiFontDescriptor;

struct uiFontDescriptor {
	// TODO const-correct this or figure out how to deal with this when getting a value
	char *Family;
	double Size;
	uiTextWeight Weight;
	uiTextItalic Italic;
	uiTextStretch Stretch;
};

_UI_EXTERN void uiLoadControlFont(uiFontDescriptor *f);
_UI_EXTERN void uiFreeFontDescriptor(uiFontDescriptor *desc);

// uiDrawTextLayout is a concrete representation of a
// uiAttributedString that can be displayed in a uiDrawContext.
// It includes information important for the drawing of a block of
// text, including the bounding box to wrap the text within, the
// alignment of lines of text within that box, areas to mark as
// being selected, and other things.
//
// Unlike uiAttributedString, the content of a uiDrawTextLayout is
// immutable once it has been created.
//
// TODO talk about OS-specific differences with text drawing that libui can't account for...
typedef struct uiDrawTextLayout uiDrawTextLayout;

// uiDrawTextAlign specifies the alignment of lines of text in a
// uiDrawTextLayout.
// TODO should this really have Draw in the name?
_UI_ENUM(uiDrawTextAlign) {
	uiDrawTextAlignLeft,
	uiDrawTextAlignCenter,
	uiDrawTextAlignRight,
};

// uiDrawTextLayoutParams describes a uiDrawTextLayout.
// DefaultFont is used to render any text that is not attributed
// sufficiently in String. Width determines the width of the bounding
// box of the text; the height is determined automatically.
typedef struct uiDrawTextLayoutParams uiDrawTextLayoutParams;

// TODO const-correct this somehow
struct uiDrawTextLayoutParams {
	uiAttributedString *String;
	uiFontDescriptor *DefaultFont;
	double Width;
	uiDrawTextAlign Align;
};

// @role uiDrawTextLayout constructor
// uiDrawNewTextLayout() creates a new uiDrawTextLayout from
// the given parameters.
//
// TODO
// - allow creating a layout out of a substring
// - allow marking compositon strings
// - allow marking selections, even after creation
// - add the following functions:
// 	- uiDrawTextLayoutHeightForWidth() (returns the height that a layout would need to be to display the entire string at a given width)
// 	- uiDrawTextLayoutRangeForSize() (returns what substring would fit in a given size)
// 	- uiDrawTextLayoutNewWithHeight() (limits amount of string used by the height)
// - some function to fix up a range (for text editing)
_UI_EXTERN uiDrawTextLayout *uiDrawNewTextLayout(uiDrawTextLayoutParams *params);

// @role uiDrawFreeTextLayout destructor
// uiDrawFreeTextLayout() frees tl. The underlying
// uiAttributedString is not freed.
_UI_EXTERN void uiDrawFreeTextLayout(uiDrawTextLayout *tl);

// uiDrawText() draws tl in c with the top-left point of tl at (x, y).
_UI_EXTERN void uiDrawText(uiDrawContext *c, uiDrawTextLayout *tl, double x, double y);

// uiDrawTextLayoutExtents() returns the width and height of tl
// in width and height. The returned width may be smaller than
// the width passed into uiDrawNewTextLayout() depending on
// how the text in tl is wrapped. Therefore, you can use this
// function to get the actual size of the text layout.
_UI_EXTERN void uiDrawTextLayoutExtents(uiDrawTextLayout *tl, double *width, double *height);

// TODO metrics functions

// TODO number of lines visible for clipping rect, range visible for clipping rect?


/**
 * A button-like control that opens a font chooser when clicked.
 *
 * @ŧodo SetFont, mechanics
 * @todo Have a function that sets an entire font descriptor to a range in a uiAttributedString at once, for SetFont?
 *
 * @struct uiFontButton
 * @extends uiControl
 * @ingroup button dataEntry
 */
typedef struct uiFontButton uiFontButton;
#define uiFontButton(this) ((uiFontButton *) (this))

/**
 * Returns the selected font.
 *
 * @param b uiFontButton instance.
 * @param[out] desc Font descriptor. [Default: OS-dependent].
 * @note Make sure to call `uiFreeFontButtonFont()` to free all allocated
 *       resources within @p desc.
 * @memberof uiFontButton
 */
_UI_EXTERN void uiFontButtonFont(uiFontButton *b, uiFontDescriptor *desc);

/**
 *  Registers a callback for when the font is changed.
 *
 * @param b uiFontButton instance.
 * @param f Callback function.\n
 *          @p sender Back reference to the instance that triggered the callback.\n
 *          @p senderData User data registered with the sender instance.
 * @param data User data to be passed to the callback.
 *
 * @note Only one callback can be registered at a time.
 * @memberof uiFontButton
 */
_UI_EXTERN void uiFontButtonOnChanged(uiFontButton *b,
	void (*f)(uiFontButton *sender, void *senderData), void *data);

/**
 * Creates a new font button.
 *
 * The default font is determined by the OS defaults.
 *
 * @returns A new uiFontButton instance.
 * @memberof uiFontButton @static
 */
_UI_EXTERN uiFontButton *uiNewFontButton(void);

/**
 * Frees a uiFontDescriptor previously filled by uiFontButtonFont().
 *
 * After calling this function the contents of @p desc should be assumed undefined,
 * however you can safely reuse @p desc.
 *
 * Calling this function on a uiFontDescriptor not previously filled by
 * uiFontButtonFont() results in undefined behavior.
 *
 * @param desc Font descriptor to free.
 * @memberof uiFontButton
 */
_UI_EXTERN void uiFreeFontButtonFont(uiFontDescriptor *desc);

/**
 * Keyboard modifier keys.
 *
 * Usable as bitmasks.
 *
 * @enum uiModifiers
 */
_UI_ENUM(uiModifiers) {
	uiModifierCtrl  = 1 << 0, //!< Control key.
	uiModifierAlt   = 1 << 1, //!< Alternate/Option key.
	uiModifierShift = 1 << 2, //!< Shift key.
	uiModifierSuper = 1 << 3, //!< Super/Command/Windows key.
};

// TODO document drag captures
struct uiAreaMouseEvent {
	// TODO document what these mean for scrolling areas
	double X;
	double Y;

	// TODO see draw above
	double AreaWidth;
	double AreaHeight;

	int Down;
	int Up;

	int Count;

	uiModifiers Modifiers;

	uint64_t Held1To64;
};

_UI_ENUM(uiExtKey) {
	uiExtKeyEscape = 1,
	uiExtKeyInsert,			// equivalent to "Help" on Apple keyboards
	uiExtKeyDelete,
	uiExtKeyHome,
	uiExtKeyEnd,
	uiExtKeyPageUp,
	uiExtKeyPageDown,
	uiExtKeyUp,
	uiExtKeyDown,
	uiExtKeyLeft,
	uiExtKeyRight,
	uiExtKeyF1,			// F1..F12 are guaranteed to be consecutive
	uiExtKeyF2,
	uiExtKeyF3,
	uiExtKeyF4,
	uiExtKeyF5,
	uiExtKeyF6,
	uiExtKeyF7,
	uiExtKeyF8,
	uiExtKeyF9,
	uiExtKeyF10,
	uiExtKeyF11,
	uiExtKeyF12,
	uiExtKeyN0,			// numpad keys; independent of Num Lock state
	uiExtKeyN1,			// N0..N9 are guaranteed to be consecutive
	uiExtKeyN2,
	uiExtKeyN3,
	uiExtKeyN4,
	uiExtKeyN5,
	uiExtKeyN6,
	uiExtKeyN7,
	uiExtKeyN8,
	uiExtKeyN9,
	uiExtKeyNDot,
	uiExtKeyNEnter,
	uiExtKeyNAdd,
	uiExtKeyNSubtract,
	uiExtKeyNMultiply,
	uiExtKeyNDivide,
};

struct uiAreaKeyEvent {
	char Key;
	uiExtKey ExtKey;
	uiModifiers Modifier;

	uiModifiers Modifiers;

	int Up;
};


/**
 * A control with a color indicator that opens a color chooser when clicked.
 *
 * The control visually represents a button with a color field representing
 * the selected color.
 *
 * Clicking on the button opens up a color chooser in form of a color palette.
 *
 * @struct uiColorButton
 * @extends uiControl
 * @ingroup dataEntry button
 */
typedef struct uiColorButton uiColorButton;
#define uiColorButton(this) ((uiColorButton *) (this))

/**
 * Returns the color button color.
 *
 * @param b uiColorButton instance.
 * @param[out] r Red. Double in range of [0, 1.0].
 * @param[out] g Green. Double in range of [0, 1.0].
 * @param[out] bl Blue. Double in range of [0, 1.0].
 * @param[out] a Alpha. Double in range of [0, 1.0].
 * @memberof uiColorButton
 */
_UI_EXTERN void uiColorButtonColor(uiColorButton *b, double *r, double *g, double *bl, double *a);

/**
 * Sets the color button color.
 *
 * @param b uiColorButton instance.
 * @param r Red. Double in range of [0, 1.0].
 * @param g Green. Double in range of [0, 1.0].
 * @param bl Blue. Double in range of [0, 1.0].
 * @param a Alpha. Double in range of [0, 1.0].
 * @memberof uiColorButton
 */
_UI_EXTERN void uiColorButtonSetColor(uiColorButton *b, double r, double g, double bl, double a);

/** Registers a callback for when the color is changed.
 *
 * @param b uiColorButton instance.
 * @param f Callback function.\n
 *          @p sender Back reference to the instance that triggered the callback.\n
 *          @p senderData User data registered with the sender instance.
 * @param data User data to be passed to the callback.
 *
 * @note The callback is not triggered when calling uiColorButtonSetColor().
 * @note Only one callback can be registered at a time.
 * @memberof uiColorButton
 */
_UI_EXTERN void uiColorButtonOnChanged(uiColorButton *b,
	void (*f)(uiColorButton *sender, void *senderData), void *data);

/**
 * Creates a new color button.
 *
 * @returns A new uiColorButton instance.
 * @memberof uiColorButton @static
 */
_UI_EXTERN uiColorButton *uiNewColorButton(void);


/**
 * A container control to organize contained controls as labeled fields.
 *
 * As the name suggests this container is perfect to create ascetically pleasing
 * input forms.
 *
 * Each control is preceded by it's corresponding label.
 *
 * Labels and containers are organized into two panes, making both labels
 * and containers align with each other.
 *
 * @struct uiForm
 * @extends uiControl
 * @ingroup container
 */
typedef struct uiForm uiForm;
#define uiForm(this) ((uiForm *) (this))

/**
 * Appends a control with a label to the form.
 *
 * Stretchy items expand to use the remaining space within the container.
 * In the case of multiple stretchy items the space is shared equally.
 *
 * @param f uiForm instance.
 * @param label Label text.\n
 *              A `NUL` terminated UTF-8 string.\n
 *              Data is copied internally. Ownership is not transferred.
 * @param c Control to append.
 * @param stretchy `TRUE` to stretch control, `FALSE` otherwise.
 * @memberof uiForm
 */
_UI_EXTERN void uiFormAppend(uiForm *f, const char *label, uiControl *c, int stretchy);

/**
 * Returns the number of controls contained within the form.
 *
 * @param f uiForm instance.
 * @memberof uiForm
 */
_UI_EXTERN int uiFormNumChildren(uiForm *f);

/**
 * Removes the control at @p index from the form.
 *
 * @param f uiForm instance.
 * @param index Index of the control to be removed.
 * @note The control is neither destroyed nor freed.
 * @memberof uiForm
 */
_UI_EXTERN void uiFormDelete(uiForm *f, int index);

/**
 * Returns whether or not controls within the form are padded.
 *
 * Padding is defined as space between individual controls.
 *
 * @param f uiForm instance.
 * @returns `TRUE` if controls are padded, `FALSE` otherwise. [Default: `TODO`]
 * @memberof uiForm
 */
_UI_EXTERN int uiFormPadded(uiForm *f);

/**
 * Sets whether or not controls within the box are padded.
 *
 * Padding is defined as space between individual controls.
 * The padding size is determined by the OS defaults.
 *
 * @param f uiForm instance.
 * @param padded  `TRUE` to make controls padded, `FALSE` otherwise.
 * @memberof uiForm
 */
_UI_EXTERN void uiFormSetPadded(uiForm *f, int padded);

/**
 * Creates a new form.
 *
 * @returns A new uiForm instance.
 * @memberof uiForm @static
 */
_UI_EXTERN uiForm *uiNewForm(void);


/**
 * Alignment specifiers to define placement within the reserved area.
 *
 * Used in uiGrid.
 * @enum uiAlign
 */
_UI_ENUM(uiAlign) {
	uiAlignFill,	//!< Fill area.
	uiAlignStart,	//!< Place at start.
	uiAlignCenter,	//!< Place in center.
	uiAlignEnd,	//!< Place at end.
};

/**
 * Placement specifier to define placement in relation to another control.
 *
 * Used in uiGrid.
 * @enum uiAt
 */
_UI_ENUM(uiAt) {
	uiAtLeading,	//!< Place before control.
	uiAtTop,	//!< Place above control.
	uiAtTrailing,	//!< Place behind control.
	uiAtBottom,	//!< Place below control.
};

/**
 * A control container to arrange containing controls in a grid.
 *
 * Contained controls are arranged on an imaginary grid of rows and columns.
 * Controls can be placed anywhere on this grid, spanning multiple rows and/or
 * columns.
 *
 * Additionally placed controls can be programmed to expand horizontally and/or
 * vertically, sharing the remaining space among other expanded controls.
 *
 * Alignment options are available via @ref uiAlign attributes to determine the
 * controls placement within the reserved area, should the area be bigger than
 * the control itself.
 *
 * Controls can also be placed in relation to other controls using @ref uiAt
 * attributes.
 *
 * @struct uiGrid
 * @extends uiControl
 * @ingroup container
 */
typedef struct uiGrid uiGrid;
#define uiGrid(this) ((uiGrid *) (this))

/**
 * Appends a control to the grid.
 *
 * @param g uiGrid instance.
 * @param c The control to insert.
 * @param left Placement as number of columns from the left. Integer in range of `[INT_MIN, INT_MAX]`.
 * @param top Placement as number of rows from the top. Integer in range of `[INT_MIN, INT_MAX]`.
 * @param xspan Number of columns to span. Integer in range of `[0, INT_MAX]`.
 * @param yspan Number of rows to span. Integer in range of `[0, INT_MAX]`.
 * @param hexpand `TRUE` to expand reserved area horizontally, `FALSE` otherwise.
 * @param halign Horizontal alignment of the control within the reserved space.
 * @param vexpand `TRUE` to expand reserved area vertically, `FALSE` otherwise.
 * @param valign Vertical alignment of the control within the reserved space.
 * @memberof uiGrid
 */
_UI_EXTERN void uiGridAppend(uiGrid *g, uiControl *c, int left, int top, int xspan, int yspan, int hexpand, uiAlign halign, int vexpand, uiAlign valign);

/**
 * Inserts a control positioned in relation to another control within the grid.
 *
 * @param g uiGrid instance.
 * @param c The control to insert.
 * @param existing The existing control to position relatively to.
 * @param at Placement specifier in relation to @p existing control.
 * @param xspan Number of columns to span. Integer in range of `[0, INT_MAX]`.
 * @param yspan Number of rows to span. Integer in range of `[0, INT_MAX]`.
 * @param hexpand `TRUE` to expand reserved area horizontally, `FALSE` otherwise.
 * @param halign Horizontal alignment of the control within the reserved space.
 * @param vexpand `TRUE` to expand reserved area vertically, `FALSE` otherwise.
 * @param valign Vertical alignment of the control within the reserved space.
 * @memberof uiGrid
 */
_UI_EXTERN void uiGridInsertAt(uiGrid *g, uiControl *c, uiControl *existing, uiAt at, int xspan, int yspan, int hexpand, uiAlign halign, int vexpand, uiAlign valign);

/**
 * Returns whether or not controls within the grid are padded.
 *
 * Padding is defined as space between individual controls.
 *
 * @param g uiGrid instance.
 * @returns `TRUE` if controls are padded, `FALSE` otherwise. [Default: `TODO`]
 * @memberof uiGrid
 */
_UI_EXTERN int uiGridPadded(uiGrid *g);

/**
 * Sets whether or not controls within the grid are padded.
 *
 * Padding is defined as space between individual controls.
 * The padding size is determined by the OS defaults.
 *
 * @param g uiGrid instance.
 * @param padded  `TRUE` to make controls padded, `FALSE` otherwise.
 * @memberof uiGrid
 */
_UI_EXTERN void uiGridSetPadded(uiGrid *g, int padded);

/**
 * Creates a new grid.
 *
 * @returns A new uiGrid instance.
 * @memberof uiGrid @static
 */
_UI_EXTERN uiGrid *uiNewGrid(void);


/**
 * A container for an image to be displayed on screen.
 *
 * The container can hold multiple representations of the same image with the
 * _same_ aspect ratio but in different resolutions to support high-density
 * displays.
 *
 * Common image dimension scale factors are `1x` and `2x`. Providing higher
 * density representations is entirely optional.
 *
 * The system will automatically determine the correct image to render depending
 * on the screen's pixel density.
 *
 * uiImage only supports premultiplied 32-bit RGBA images.
 *
 * No image file loading or image format conversion utilities are provided.
 *
 * @struct uiImage
 * @ingroup static
 */
typedef struct uiImage uiImage;

/**
 * Creates a new image container.
 *
 * Dimensions are measured in points. This is most commonly the pixel size
 * of the `1x` scaled image.
 *
 * @param width Width in points.
 * @param height Height in points.
 * @returns A new uiImage instance.
 * @memberof uiImage @static
 */
_UI_EXTERN uiImage *uiNewImage(double width, double height);

/**
 * Frees the image container and all associated resources.
 *
 * @param i uiImage instance.
 * @memberof uiImage
 */
_UI_EXTERN void uiFreeImage(uiImage *i);

/**
 * Appends a new image representation.
 *
 * @param i uiImage instance.
 * @param pixels Byte array of premultiplied pixels in [R G B A] order.\n
 *               `((uint8_t *) pixels)[0]` equals the **R** of the first pixel,
 *               `[3]` the **A** of the first pixel.\n
 *               `pixels` must be at least `byteStride * pixelHeight` bytes long.\n
 *               Data is copied internally. Ownership is not transferred.
 * @param pixelWidth Width in pixels.
 * @param pixelHeight Height in pixels.
 * @param byteStride Number of bytes per row of the pixel array.
 * @todo see if we either need the stride or can provide a way to get the OS-preferred stride (in cairo we do)
 * @todo use const void * for const correctness
 * @memberof uiImage
 */
_UI_EXTERN void uiImageAppend(uiImage *i, void *pixels, int pixelWidth, int pixelHeight, int byteStride);

/**
 * @addtogroup table
 * @{
 *
 * Types and methods for organizing and displaying tabular data.
 *
 * Tables follow the concept of separation of concerns, similar to common
 * patterns like model-view-controller or model-view-adapter.
 *
 * They consist of three main components:
 *
 * - uiTableModel acts as a delegate for the underlying data store. Its purpose
 *   is to provide the data for views and inform about any updates.
 * - uiTable represents the view. Its purpose is to display the data provided
 *   by the model as well as provide an interface to the user to modify data.
 * - uiTableModelHandler takes on the role of controller and model. It provides
 *   the actual data while also handling data edits.
 *
 * To get started:
 *
 * 1. Implement all of the methods defined in uiTableModelHandler.
 *    This involves defining columns, their data types as well as getters and
 *    setters for each table cell.
 * 2. Wrap the uiTableModelHandler from step 1 in a uiTableModel object.
 * 3. Create a new uiTable using the model created in step 2.
 *    Start adding columns to your table. Each table column is backed by
 *    one or more model columns.
 *
 * You can create multiple differing views (uiTable) using the same
 * uiTableModel.
 *
 * @}
 */

/**
 * Container to store values used in container related methods.
 *
 * uiTableValue objects are immutable.
 *
 * uiTable and uiTableModel methods take ownership of the uiTableValue objects
 * when passed as parameter. Exception: uiNewTableValueImage().
 *
 * uiTable and uiTableModel methods retain ownership when returning uiTableValue
 * objects. Exception: uiTableValueImage().
 *
 * @struct uiTableValue
 * @ingroup table
 */
typedef struct uiTableValue uiTableValue;

/**
 * Frees the uiTableValue.
 *
 * @param v Table value to free.
 *
 * @warning This function is to be used only on uiTableValue objects that
 *          have NOT been passed to uiTable or uiTableModel - as these
 *          take ownership of the object.\n
 *          Use this for freeing erroneously created values or when directly
 *          calling uiTableModelHandler without transferring ownership to
 *          uiTable or uiTableModel.
 * @memberof uiTableValue
 */
_UI_EXTERN void uiFreeTableValue(uiTableValue *v);

/**
 * uiTableValue types.
 *
 * @todo Define whether calling any of the getters on the wrong type is
 *       undefined behavior or caught error.
 * @enum uiTableValueType
 */
_UI_ENUM(uiTableValueType) {
	uiTableValueTypeString,
	uiTableValueTypeImage,
	uiTableValueTypeInt,
	uiTableValueTypeColor,
};

/**
 * Gets the uiTableValue type.
 *
 * @param v Table value.
 * @returns Table value type.
 * @memberof uiTableValue
 */
_UI_EXTERN uiTableValueType uiTableValueGetType(const uiTableValue *v);

/**
 * Creates a new table value to store a text string.
 *
 * @param str String value.\n
 *            A valid, `NUL` terminated UTF-8 string.\n
 *            Data is copied internally. Ownership is not transferred.
 * @returns A new uiTableValue instance.
 * @memberof uiTableValue @static
 */
_UI_EXTERN uiTableValue *uiNewTableValueString(const char *str);

/**
 * Returns the string value held internally.
 *
 * To be used only on uiTableValue objects of type uiTableValueTypeString.
 *
 * @param v Table value.
 * @returns String value.\n
 *          A `NUL` terminated UTF-8 string.\n
 *          Data remains owned by @p v, do **NOT** call `uiFreeText()`.
 * @memberof uiTableValue
 */
_UI_EXTERN const char *uiTableValueString(const uiTableValue *v);

/**
 * Creates a new table value to store an image.
 *
 * @param img Image.\n
 *            Data is NOT copied and needs to kept alive.
 * @returns A new uiTableValue instance.
 * @warning Unlike other uiTableValue constructors, uiNewTableValueImage() does
 *          NOT copy the image to save time and space. Make sure the image
 *          data stays valid while in use by the library.
 *          As a general rule: if the constructor is called via the
 *          uiTableModelHandler, the image is safe to free once execution
 *          returns to ANY of your code.
 * @memberof uiTableValue @static
 */
_UI_EXTERN uiTableValue *uiNewTableValueImage(uiImage *img);

/**
 * Returns a reference to the image contained.
 *
 * To be used only on uiTableValue objects of type uiTableValueTypeImage.
 *
 * @param v Table value.
 * @returns Image.\n
 *          Data is owned by the caller of uiNewTableValueImage().
 * @warning The image returned is not owned by the object @p v,
 *          hence no lifetime guarantees can be made.
 * @memberof uiTableValue
 */
_UI_EXTERN uiImage *uiTableValueImage(const uiTableValue *v);

/**
 * Creates a new table value to store an integer.
 *
 * This value type can be used in conjunction with properties like
 * column editable [`TRUE`, `FALSE`] or controls like progress bars and
 * checkboxes. For these, consult uiProgressBar and uiCheckbox for the allowed
 * integer ranges.
 *
 * @param i Integer value.
 * @returns A new uiTableValue instance.
 * @memberof uiTableValue @static
 */
_UI_EXTERN uiTableValue *uiNewTableValueInt(int i);

/**
 * Returns the integer value held internally.
 *
 * To be used only on uiTableValue objects of type uiTableValueTypeInt.
 *
 * @param v Table value.
 * @returns Integer value.
 * @memberof uiTableValue
 */
_UI_EXTERN int uiTableValueInt(const uiTableValue *v);

/**
 * Creates a new table value to store a color in.
 *
 * @param r Red. Double in range of [0, 1.0].
 * @param g Green. Double in range of [0, 1.0].
 * @param b Blue. Double in range of [0, 1.0].
 * @param a Alpha. Double in range of [0, 1.0].
 * @returns A new uiTableValue instance.
 * @memberof uiTableValue @static
 */
_UI_EXTERN uiTableValue *uiNewTableValueColor(double r, double g, double b, double a);

/**
 * Returns the color value held internally.
 *
 * To be used only on uiTableValue objects of type uiTableValueTypeColor.
 *
 * @param v Table value.
 * @param[out] r Red. Double in range of [0, 1.0].
 * @param[out] g Green. Double in range of [0, 1.0].
 * @param[out] b Blue. Double in range of [0, 1.0].
 * @param[out] a Alpha. Double in range of [0, 1.0].
 * @memberof uiTableValue
 */
_UI_EXTERN void uiTableValueColor(const uiTableValue *v, double *r, double *g, double *b, double *a);


/**
 * Sort indicators.
 *
 * Generic sort indicators to display sorting direction.
 *
 * @enum uiSortIndicator
 * @ingroup table
 */
_UI_ENUM(uiSortIndicator) {
	uiSortIndicatorNone,
	uiSortIndicatorAscending,
	uiSortIndicatorDescending
};

/**
 * Table model delegate to retrieve data and inform about model changes.
 *
 * This is a wrapper around uiTableModelHandler where the actual data is
 * held.
 *
 * The main purpose it to provide methods to the developer to signal that
 * underlying data has changed.
 *
 * Row indexes match both the row indexes in uiTable and uiTableModelHandler.
 *
 * A uiTableModel can be used as the backing store for multiple uiTable views.
 *
 * Once created, the number of columns and their data types are not allowed
 * to change.
 *
 * @warning Not informing the uiTableModel about out-of-band data changes is
 *          an error. User edits via uiTable do *not* fall in this category.
 * @struct uiTableModel
 * @ingroup table
 */
typedef struct uiTableModel uiTableModel;

/**
 * Developer defined methods for data retrieval and setting.
 *
 * These methods get called whenever the associated uiTableModel needs to
 * retrieve data or a uiTable wants to set data.
 *
 * @warning These methods are NOT allowed to change as soon as the
 *          uiTableModelHandler is associated with a uiTableModel.
 * @todo Validate ranges
 * @todo Validate types on each getter/setter call (? table columns only?)
 * @struct uiTableModelHandler
 * @ingroup table
 */
typedef struct uiTableModelHandler uiTableModelHandler;
struct uiTableModelHandler {
	/**
	 * Returns the number of columns in the uiTableModel.
	 *
	 * @warning This value MUST remain constant throughout the lifetime of the uiTableModel.
	 * @warning This method is not guaranteed to be called depending on the system.
	 * @todo strongly check column numbers and types on all platforms so
	 *       these clauses can go away
	 */
	int (*NumColumns)(uiTableModelHandler *, uiTableModel *);

	/**
	 * Returns the column type in for of a #uiTableValueType.
	 *
	 * @warning This value MUST remain constant throughout the lifetime of the uiTableModel.
	 * @warning This method is not guaranteed to be called depending on the system.
	 */
	uiTableValueType (*ColumnType)(uiTableModelHandler *, uiTableModel *, int column);

	/**
	 * Returns the number of rows in the uiTableModel.
	 */
	int (*NumRows)(uiTableModelHandler *, uiTableModel *);

	/**
	 * Returns the cell value for (row, column).
	 *
	 * Make sure to use the uiTableValue constructors. The returned value
	 * must match the #uiTableValueType defined in ColumnType().
	 *
	 * Some columns may return `NULL` as a special value. Refer to the
	 * appropriate `uiTableAppend*Column()` documentation.
	 *
	 * @note uiTableValue objects are automatically freed when requested by
	 *       a uiTable.
	 */
	uiTableValue *(*CellValue)(uiTableModelHandler *mh, uiTableModel *m, int row, int column);

	/**
	 * Sets the cell value for (row, column).
	 *
	 * It is up to the handler to decide what to do with the value: change
	 * the model or reject the change, keeping the old value.
	 *
	 * Some columns may call this function with `NULL` as a special value.
	 * Refer to the appropriate `uiTableAppend*Column()` documentation.
	 *
	 * @note uiTableValue objects are automatically freed upon return when
	 * set by a uiTable.
	 */
	void (*SetCellValue)(uiTableModelHandler *, uiTableModel *, int, int, const uiTableValue *);
};

/**
 * Creates a new table model.
 *
 * @param mh Table model handler.
 * @returns A new uiTableModel instance.
 * @memberof uiTableModel @static
 */
_UI_EXTERN uiTableModel *uiNewTableModel(uiTableModelHandler *mh);

/**
 * Frees the table model.
 *
 * @param m Table model to free.
 * @warning It is an error to free table models currently associated with a
 *          uiTable.
 * @memberof uiTableModel
 */
_UI_EXTERN void uiFreeTableModel(uiTableModel *m);

/**
 * Informs all associated uiTable views that a new row has been added.
 *
 * You must insert the row data in your model before calling this function.
 *
 * NumRows() must represent the new row count before you call this function.
 *
 * @param m Table model that has changed.
 * @param newIndex Index of the row that has been added.
 * @memberof uiTableModel
 */
_UI_EXTERN void uiTableModelRowInserted(uiTableModel *m, int newIndex);

/**
 * Informs all associated uiTable views that a row has been changed.
 *
 * You do NOT need to call this in your SetCellValue() handlers, but NEED
 * to call this if your data changes at any other point.
 *
 * @param m Table model that has changed.
 * @param index Index of the row that has changed.
 * @memberof uiTableModel
 */
_UI_EXTERN void uiTableModelRowChanged(uiTableModel *m, int index);

/**
 * Informs all associated uiTable views that a row has been deleted.
 *
 * You must delete the row from your model before you call this function.
 *
 * NumRows() must represent the new row count before you call this function.
 *
 * @param m Table model that has changed.
 * @param oldIndex Index of the row that has been deleted.
 * @memberof uiTableModel
 */
_UI_EXTERN void uiTableModelRowDeleted(uiTableModel *m, int oldIndex);
// TODO reordering/moving

/** Parameter to editable model columns to signify all rows are never editable. */
#define uiTableModelColumnNeverEditable (-1)
/** Parameter to editable model columns to signify all rows are always editable. */
#define uiTableModelColumnAlwaysEditable (-2)

/**
 * Optional parameters to control the appearance of text columns.
 *
 * @struct uiTableTextColumnOptionalParams
 * @ingroup table
 */
typedef struct uiTableTextColumnOptionalParams uiTableTextColumnOptionalParams;
struct uiTableTextColumnOptionalParams {
	/**
	 * uiTableModel column that defines the text color for each cell.
	 *
	 * #uiTableValueTypeColor Text color, `NULL` to use the default color
	 * for that cell.
	 *
	 * `-1` to use the default color for all cells.
	 */
	int ColorModelColumn;
};

/**
 * Table parameters passed to uiNewTable().
 *
 * @struct uiTableParams
 * @ingroup table
 */
typedef struct uiTableParams uiTableParams;
struct uiTableParams {
	/**
	 * Model holding the data to be displayed. This can NOT be `NULL`.
	 */
	uiTableModel *Model;
	/**
	 * uiTableModel column that defines background color for each row,
	 *
	 * #uiTableValueTypeColor Background color, `NULL` to use the default
	 * background color for that row.
	 *
	 * `-1` to use the default background color for all rows.
	 */
	int RowBackgroundColorModelColumn;
};

/**
 * A control to display data in a tabular fashion.
 *
 * The view of the architecture.
 *
 * Data is retrieved from a uiTableModel via methods that you need to define
 * in a uiTableModelHandler.
 *
 * Make sure the uiTableModel columns return the right type, as specified in
 * the `uiTableAppend*Column()` parameters.
 *
 * The `*EditableModelColumn` parameters typically point to a uiTableModel
 * column index, that specifies the property on a per row basis.\n
 * They can however also be passed two special values defining the property
 * for all rows: `uiTableModelColumnNeverEditable` and
 * `uiTableModelColumnAlwaysEditable`.
 *
 * @struct uiTable
 * @extends uiControl
 * @ingroup dataEntry table
 */
typedef struct uiTable uiTable;
#define uiTable(this) ((uiTable *) (this))

/**
 * Appends a text column to the table.
 *
 * @param t uiTable instance.
 * @param name Column title text.\n
 *             A valid, `NUL` terminated UTF-8 string.\n
 *             Data is copied internally. Ownership is not transferred.
 * @param textModelColumn Column that holds the text to be displayed.\n
 *                        #uiTableValueTypeString
 * @param textEditableModelColumn Column that defines whether or not the text is editable.\n
 *                                #uiTableValueTypeInt `TRUE` to make text editable, `FALSE`
 *                                otherwise.\n
 *                                `uiTableModelColumnNeverEditable` to make all rows never editable.\n
 *                                `uiTableModelColumnAlwaysEditable` to make all rows always editable.
 * @param textParams Text display settings, `NULL` to use defaults.
 * @memberof uiTable
 */
_UI_EXTERN void uiTableAppendTextColumn(uiTable *t,
	const char *name,
	int textModelColumn,
	int textEditableModelColumn,
	uiTableTextColumnOptionalParams *textParams);

/**
 * Appends an image column to the table.
 *
 * Images are drawn at icon size, using the representation that best fits the
 * pixel density of the screen.
 *
 * @param t uiTable instance.
 * @param name Column title text.\n
 *             A valid, `NUL` terminated UTF-8 string.\n
 *             Data is copied internally. Ownership is not transferred.
 * @param imageModelColumn Column that holds the images to be displayed.\n
 *                         #uiTableValueTypeImage
 * @memberof uiTable
 */
_UI_EXTERN void uiTableAppendImageColumn(uiTable *t,
	const char *name,
	int imageModelColumn);

/**
 * Appends a column to the table that displays both an image and text.
 *
 * Images are drawn at icon size, using the representation that best fits the
 * pixel density of the screen.
 *
 * @param t uiTable instance.
 * @param name Column title text.\n
 *             A valid, `NUL` terminated UTF-8 string.\n
 *             Data is copied internally. Ownership is not transferred.
 * @param imageModelColumn Column that holds the images to be displayed.\n
 *                         #uiTableValueTypeImage
 * @param textModelColumn Column that holds the text to be displayed.\n
 *                        #uiTableValueTypeString
 * @param textEditableModelColumn Column that defines whether or not the text is editable.\n
 *                                #uiTableValueTypeInt `TRUE` to make text editable, `FALSE` otherwise.\n
 *                                `uiTableModelColumnNeverEditable` to make all rows never editable.\n
 *                                `uiTableModelColumnAlwaysEditable` to make all rows always editable.
 * @param textParams Text display settings, `NULL` to use defaults.
 * @memberof uiTable
 */
_UI_EXTERN void uiTableAppendImageTextColumn(uiTable *t,
	const char *name,
	int imageModelColumn,
	int textModelColumn,
	int textEditableModelColumn,
	uiTableTextColumnOptionalParams *textParams);

/**
 * Appends a column to the table containing a checkbox.
 *
 * @param t uiTable instance.
 * @param name Column title text.\n
 *             A valid, `NUL` terminated UTF-8 string.\n
 *             Data is copied internally. Ownership is not transferred.
 * @param checkboxModelColumn Column that holds the data to be displayed.\n
 *                            #uiTableValueTypeInt `TRUE` for a checked checkbox, `FALSE` otherwise.
 * @param checkboxEditableModelColumn Column that defines whether or not the checkbox is editable.\n
 *                                    #uiTableValueTypeInt `TRUE` to make checkbox editable, `FALSE` otherwise.\n
 *                                    `uiTableModelColumnNeverEditable` to make all rows never editable.\n
 *                                    `uiTableModelColumnAlwaysEditable` to make all rows always editable.
 * @memberof uiTable
 */
_UI_EXTERN void uiTableAppendCheckboxColumn(uiTable *t,
	const char *name,
	int checkboxModelColumn,
	int checkboxEditableModelColumn);

/**
 * Appends a column to the table containing a checkbox and text.
 *
 * @param t uiTable instance.
 * @param name Column title text.\n
 *             A valid, `NUL` terminated UTF-8 string.\n
 *             Data is copied internally. Ownership is not transferred.
 * @param checkboxModelColumn Column that holds the data to be displayed.\n
 *                            #uiTableValueTypeInt
 *                            `TRUE` for a checked checkbox, `FALSE` otherwise.
 * @param checkboxEditableModelColumn Column that defines whether or not the checkbox is editable.\n
 *                                    #uiTableValueTypeInt `TRUE` to make checkbox editable, `FALSE` otherwise.\n
 *                                    `uiTableModelColumnNeverEditable` to make all rows never editable.\n
 *                                    `uiTableModelColumnAlwaysEditable` to make all rows always editable.
 * @param textModelColumn Column that holds the text to be displayed.\n
 *                        #uiTableValueTypeString
 * @param textEditableModelColumn Column that defines whether or not the text is editable.\n
 *                                #uiTableValueTypeInt `TRUE` to make text editable, `FALSE` otherwise.\n
 *                                `uiTableModelColumnNeverEditable` to make all rows never editable.\n
 *                                `uiTableModelColumnAlwaysEditable` to make all rows always editable.
 * @param textParams Text display settings, `NULL` to use defaults.
 * @memberof uiTable
 */
_UI_EXTERN void uiTableAppendCheckboxTextColumn(uiTable *t,
	const char *name,
	int checkboxModelColumn,
	int checkboxEditableModelColumn,
	int textModelColumn,
	int textEditableModelColumn,
	uiTableTextColumnOptionalParams *textParams);

/**
 * Appends a column to the table containing a progress bar.
 *
 * The workings and valid range are exactly the same as that of uiProgressBar.
 *
 * @param t uiTable instance.
 * @param name Column title text.\n
 *             A valid, `NUL` terminated UTF-8 string.\n
 *             Data is copied internally. Ownership is not transferred.
 * @param progressModelColumn Column that holds the data to be displayed.\n
 *                            #uiTableValueTypeInt Integer in range of `[-1, 100]`, see uiProgressBar
 *                            for details.
 * @see uiProgressBar
 * @memberof uiTable
 */
_UI_EXTERN void uiTableAppendProgressBarColumn(uiTable *t,
	const char *name,
	int progressModelColumn);

/**
 * Appends a column to the table containing a button.
 *
 * Button clicks are signaled to the uiTableModelHandler via a call to
 * SetCellValue() with a value of `NULL` for the @p buttonModelColumn.
 *
 * CellValue() must return the button text to display.
 *
 * @param t uiTable instance.
 * @param name Column title text.\n
 *             A valid, `NUL` terminated UTF-8 string.\n
 *             Data is copied internally. Ownership is not transferred.
 * @param buttonModelColumn Column that holds the button text to be displayed.\n
 *                          #uiTableValueTypeString
 * @param buttonClickableModelColumn Column that defines whether or not the button is clickable.\n
 *                                   #uiTableValueTypeInt `TRUE` to make button clickable, `FALSE` otherwise.\n
 *                                   `uiTableModelColumnNeverEditable` to make all rows never clickable.\n
 *                                   `uiTableModelColumnAlwaysEditable` to make all rows always clickable.
 * @memberof uiTable
 */
_UI_EXTERN void uiTableAppendButtonColumn(uiTable *t,
	const char *name,
	int buttonModelColumn,
	int buttonClickableModelColumn);

/**
 * Returns whether or not the table header is visible.
 *
 * @param t uiTable instance.
 * @returns `TRUE` if visible, `FALSE` otherwise. [Default `TRUE`]
 * @memberof uiTable
 */
_UI_EXTERN int uiTableHeaderVisible(uiTable *t);

/**
 * Sets whether or not the table header is visible.
 *
 * @param t uiTable instance.
 * @param visible `TRUE` to show header, `FALSE` to hide header.
 * @memberof uiTable
 */
_UI_EXTERN void uiTableHeaderSetVisible(uiTable *t, int visible);

/**
 * Creates a new table.
 *
 * @param params Table parameters.
 * @returns A new uiTable instance.
 * @memberof uiTable @static
 */
_UI_EXTERN uiTable *uiNewTable(uiTableParams *params);


/**
 * Registers a callback for when the user single clicks a table row.
 *
 * @param t uiTable instance.
 * @param f Callback function.\n
 *          @p sender Back reference to the instance that triggered the callback.\n
 *          @p row Row index that was clicked.\n
 *          @p senderData User data registered with the sender instance.
 * @param data User data to be passed to the callback.
 *
 * @note Only one callback can be registered at a time.
 * @memberof uiTable
 */
_UI_EXTERN void uiTableOnRowClicked(uiTable *t,
	void (*f)(uiTable *t, int row, void *data),
	void *data);

/**
 * Registers a callback for when the user double clicks a table row.
 *
 * @param t uiTable instance.
 * @param f Callback function.\n
 *          @p sender Back reference to the instance that triggered the callback.\n
 *          @p row Row index that was double clicked.\n
 *          @p senderData User data registered with the sender instance.
 * @param data User data to be passed to the callback.
 *
 * @note The double click callback is always preceded by one uiTableOnRowClicked() callback.
 * @bug For unix systems linking against `GTK < 3.14` the preceding uiTableOnRowClicked()
 *      callback will be triggered twice.
 * @note Only one callback can be registered at a time.
 * @memberof uiTable
 */
_UI_EXTERN void uiTableOnRowDoubleClicked(uiTable *t,
	void (*f)(uiTable *t, int row, void *data),
	void *data);

/**
 * Sets the column's sort indicator displayed in the table header.
 *
 * Use this to display appropriate arrows in the table header to indicate a
 * sort direction.
 *
 * @param t uiTable instance.
 * @param column Column index.
 * @param indicator Sort indicator.
 * @note Setting the indicator is purely visual and does not perform any sorting.
 * @memberof uiTable
 */
_UI_EXTERN void uiTableHeaderSetSortIndicator(uiTable *t,
	int column,
	uiSortIndicator indicator);

/**
 * Returns the column's sort indicator displayed in the table header.
 *
 * @param t uiTable instance.
 * @param column Column index.
 * @returns The current sort indicator. [Default: `uiSortIndicatorNone`]
 * @memberof uiTable
 */
_UI_EXTERN uiSortIndicator uiTableHeaderSortIndicator(uiTable *t, int column);

/**
 * Registers a callback for when a table column header is clicked.
 *
 * @param t uiTable instance.
 * @param f Callback function.\n
 *          @p sender Back reference to the instance that triggered the callback.\n
 *          @p column Column index that was clicked.\n
 *          @p senderData User data registered with the sender instance.
 * @param data User data to be passed to the callback.
 *
 * @note Only one callback can be registered at a time.
 * @memberof uiTable
 */
_UI_EXTERN void uiTableHeaderOnClicked(uiTable *t,
	void (*f)(uiTable *sender, int column, void *senderData), void *data);

/**
 * Returns the table column width.
 *
 * @param t uiTable instance.
 * @param column Column index.
 * @returns Column width in pixels.
 * @memberof uiTable
 */
_UI_EXTERN int uiTableColumnWidth(uiTable *t, int column);

/**
 * Sets the table column width.
 *
 * Setting the width to `-1` will restore automatic column sizing matching
 * either the width of the content or column header (which ever one is bigger).
 * @note Darwin currently only resizes to the column header width on `-1`.
 *
 * @param t uiTable instance.
 * @param column Column index.
 * @param width Column width to set in pixels, `-1` to restore automatic
 *              column sizing.
 * @memberof uiTable
 */
_UI_EXTERN void uiTableColumnSetWidth(uiTable *t, int column, int width);

/**
 * Table selection modes.
 *
 * Table selection that enforce how a user can interact with a table.
 *
 * @warning An empty table selection is a valid state for any selection mode.
 *          This is in fact the default upon table creation and can otherwise
 *          triggered through operations such as row deletion.
 *
 * @enum uiTableSelectionMode
 * @ingroup table
 */
_UI_ENUM(uiTableSelectionMode) {
	/**
	 * Allow no row selection.
	 *
	 * @warning This mode disables all editing of text columns. Buttons
	 * and checkboxes keep working though.
	 */
        uiTableSelectionModeNone,
        uiTableSelectionModeZeroOrOne,  //!< Allow zero or one row to be selected.
        uiTableSelectionModeOne,        //!< Allow for exactly one row to be selected.
        uiTableSelectionModeZeroOrMany, //!< Allow zero or many (multiple) rows to be selected.
};

/**
 * Returns the table selection mode.
 *
 * @param t uiTable instance.
 * @returns The table selection mode. [Default `uiTableSelectionModeZeroOrOne`]
 *
 * @memberof uiTable
 */
_UI_EXTERN uiTableSelectionMode uiTableGetSelectionMode(uiTable *t);

/**
 * Sets the table selection mode.
 *
 * @param t uiTable instance.
 * @param mode Table selection mode to set.
 *
 * @warning All rows will be deselected if the existing selection is illegal
 *          in the new selection mode.
 * @memberof uiTable
 */
_UI_EXTERN void uiTableSetSelectionMode(uiTable *t, uiTableSelectionMode mode);

/**
 * Registers a callback for when the table selection changed.
 *
 * @param t uiTable instance.
 * @param f Callback function.\n
 *          @p sender Back reference to the instance that triggered the callback.\n
 *          @p senderData User data registered with the sender instance.
 * @param data User data to be passed to the callback.
 *
 * @note The callback is not triggered when calling uiTableSetSelection() or
 *       when needing to clear the selection on uiTableSetSelectionMode().
 * @note Only one callback can be registered at a time.
 * @memberof uiTable
 */
_UI_EXTERN void uiTableOnSelectionChanged(uiTable *t, void (*f)(uiTable *t, void *data), void *data);

/**
 * Holds an array of selected row indices for a table.
 *
 * @struct uiTableSelection
 * @ingroup table
 */
typedef struct uiTableSelection uiTableSelection;
struct uiTableSelection
{
	int NumRows; //!< Number of selected rows.
	int *Rows;   //!< Array containing selected row indices, NULL on empty selection.
};

/**
 * Returns the current table selection.
 *
 * @param t uiTable instance.
 * @returns The number of selected rows and corresponding row indices.\n
 *          Caller is responsible for freeing the data with `uiFreeTableSelection()`.
 *
 * @note For empty selections the `Rows` pointer will be NULL.
 * @memberof uiTable
 */
_UI_EXTERN uiTableSelection* uiTableGetSelection(uiTable *t);

/**
 * Sets the current table selection clearing any previous selection.
 *
 * @param t uiTable instance.
 * @param sel Table selection.\n
 *            Data is copied internally. Ownership is not transferred.
 *
 * @note Selecting more rows than the selection mode allows for results in nothing happening.
 * @note For empty selections the Rows pointer is never accessed.
 * @memberof uiTable
 */
_UI_EXTERN void uiTableSetSelection(uiTable *t, uiTableSelection *sel);

/**
 * Frees the given uiTableSelection and all it's resources.
 *
 * @param s uiTableSelection instance.
 * @memberof uiTableSelection
 */
_UI_EXTERN void uiFreeTableSelection(uiTableSelection* s);

#ifdef __cplusplus
}
#endif

#endif
